use crate::markdowner::MarkdownModule;
use lipgloss::Border;
use mq_markdown::{ListStyle, RenderOptions, UrlSurroundStyle};
use mq_view::{RenderConfig, render_markdown_with_config};
use warp::Reply;

fn box_content(content: &String, width: i32) -> String {
    let lg_border = Border::new("─", "─", "│", "│", "╭", "╮", "╰", "╯", "", "", "", "", "");
    let border_style = lipgloss::Style::new()
        .border(lg_border)
        .width(width)
        .padding(0, 2, 0, 2)
        .align_horizontal(lipgloss::position::LEFT);

    border_style.render(content.as_str())
}

fn markdown_to_cli(content: &String) -> String {
    let mut mq: mq_markdown::Markdown = content.parse().expect("could not parse markdown content!");
    let render_opts = RenderOptions {
        list_style: ListStyle::Dash,
        link_url_style: UrlSurroundStyle::None,
        link_title_style: mq_markdown::TitleSurroundStyle::Single,
    };
    mq.set_options(render_opts);
    let render_conf = RenderConfig {
        header_full_width_highlight: false,
    };
    let _styled_mq = mq_view::render_markdown_to_string(&mq).unwrap();

    let mut writer: Vec<u8> = Vec::new();

    render_markdown_with_config(&mq, &mut writer, &render_conf).unwrap();

    String::from_utf8(writer).unwrap()
}

fn render_content(content: &String, width: i32) -> String {
    let md = markdown_to_cli(content);

    box_content(&md, width)
}

fn get_cli_header(page_contents: &Vec<MarkdownModule>, width: i32) -> String {
    let header = page_contents
        .iter()
        .find(|m| m.path.file_name().unwrap_or_default().eq("header.md"));
    match header {
        Some(h) => render_content(&h.content, width),
        None => "".to_string(),
    }
}

fn get_cli_content(page_contents: &Vec<MarkdownModule>, width: i32) -> Vec<String> {
    let content = page_contents
        .iter()
        .filter(|m| m.path.file_name().unwrap_or_default().ne("header.md"));
    content
        .map(|m| render_content(&m.content, (width / 2) - 4))
        .collect()
}

fn column_layout(mut left_column: String, mut right_column: String) -> String {
    let left_pad = left_column
        .lines()
        .map(|l| {
            String::from_utf8(strip_ansi_escapes::strip(&l))
                .expect("could not strip ansi from text")
                .chars()
                .count()
        })
        .max()
        .unwrap_or(0);
    while right_column
        .lines()
        .count()
        .lt(&left_column.lines().count())
    {
        right_column = format!("{}\n", right_column);
    }
    while left_column
        .lines()
        .count()
        .lt(&right_column.lines().count())
    {
        left_column = format!("{}\n", left_column);
    }
    println!(
        "page: {}\nsidebar: {}",
        right_column.lines().count(),
        left_column.lines().count()
    );
    let cli_columns: Vec<String> = left_column
        .lines()
        .zip(right_column.lines())
        .map(|(left, right)| format!("{:width$}  {}", left, right, width = left_pad))
        .collect();
    cli_columns.join("\n")
}

pub fn curl_response(
    page_contents: Vec<MarkdownModule>,
    sidebar_contents: Vec<MarkdownModule>,
    width: Option<i32>,
) -> Box<dyn Reply> {
    let w = width.unwrap_or(100);
    let shell_header = if width.is_none() {
        "curl -s beta.pogmom.me/?width=$(tput cols);exit 0\n".to_string()
    } else {
        "".to_string()
    };
    let shell_footer = if width.is_none() {
        box_content(
        &"Did you know‽\nIf you (dangerously) pipe this output to your shell, it autosizes! more interactivity is planned in the future".to_string(),
        w - 4)
    } else {
        "".to_string()
    };
    let terminal_header = get_cli_header(&page_contents, w - 4);
    let terminal_sidebar = get_cli_content(&sidebar_contents, w).join("\n");
    let terminal_page = get_cli_content(&page_contents, w).join("\n");

    let terminal_body = if w.gt(&110) {
        column_layout(terminal_sidebar, terminal_page)
    } else {
        format!("{}\n{}\n", terminal_sidebar, terminal_page)
    };

    let cli_contents = format!(
        "{}{}\n{}\n{}\n",
        shell_header, terminal_header, terminal_body, shell_footer
    );

    Box::new(warp::reply::with_status(
        cli_contents,
        warp::http::StatusCode::OK,
    ))
}
