use crate::ToYew;
use notedown_ast::{AST, ListView, Highlighter, SmartLink};
use notedown_ast::utils::{indent};
use crate::slugify::Slugify;
use crate::codegen::utils::{check_bare_text};


impl ToYew for AST {
    fn to_yew(&self) -> String {
        match self {
            AST::None => { unimplemented!() }
            AST::Newline => { unimplemented!() }
            AST::Statements(v) => match v.len() {
                0 => String::new(),
                1 => format!("{}", v.to_yew()),
                _ => format!("<>{}</>", v.to_yew()),
            },
            AST::Header(s, h) => {
                format!(
                    "<h{n} id=\"{id}\">\n{body}</h{n}>",
                    n = h,
                    id = s.slugify('-'),
                    body = indent(s.to_yew(), 4)
                )
            }
            AST::Paragraph(p) => { format!("<p>{}</p>", p.to_yew()) }

            AST::Math(s) => { format!("<KaTeX math={}/>", s) }
            AST::Table(_) => { unimplemented!() }

            AST::Text(_) => { unimplemented!() }
            AST::Raw(_) => { unimplemented!() }
            AST::Code(_) => { unimplemented!() }
            AST::Emphasis(s) => { format!("<u>{}</u>", s.to_yew()) }
            AST::Strong(s) => { format!("<b>{}</b>", s.to_yew()) }
            AST::Underline(s) => { format!("<u>{}</u>", s.to_yew()) }
            AST::Strikethrough(s) => { format!("<b>{}</b>", s.to_yew()) }
            AST::Undercover(s) => { format!("<b>{}</b>", s.to_yew()) }
            AST::MathInline(s) => { format!("<KaTeX inline math={}/>", s) }
            AST::MathDisplay(s) => { format!("<KaTeX inline math={}/>", s) }

            AST::Link(link) => link.to_yew(),
            AST::Highlight(code) => code.to_yew(),
            AST::List(list) => list.to_yew(),

            AST::Escaped(_) => { unimplemented!() }
            AST::Command(_) => { unimplemented!() }
        }
    }
}


impl ToYew for Vec<AST> {
    fn to_yew(&self) -> String {
        let mut refined = Vec::with_capacity(self.len());
        for node in self {
            refined.push(node)
        }
        match refined.len() {
            0 => String::new(),
            1 => check_bare_text(&self[0]),
            _ => {
                let terms = self.iter().map(check_bare_text).collect::<Vec<_>>().join("\n");
                format!("\n{}", indent(terms, 4))
            }
        }
    }
}


impl ToYew for Highlighter {
    fn to_yew(&self) -> String {
        format!("<Prism\n    language={:?}\n    code={:?}\n/>", self.lang, self.code)
    }
}


impl ToYew for ListView {
    fn to_yew(&self) -> String {
        match self {
            ListView::Quote { .. } => { unimplemented!() }
            ListView::Ordered { .. } => { unimplemented!() }
            ListView::Orderless { .. } => { unimplemented!() }
        }
    }
}

impl ToYew for SmartLink {
    fn to_yew(&self) -> String {
        match self {
            SmartLink::Hyperlinks { from, to, alt, bind: _ } => {
                let href = match to {
                    None => format!("{:?}", from),
                    Some(s) => format!("{:?}", s)
                };
                let alt = match alt {
                    None => String::new(),
                    Some(s) => format!(" alt=\"{url}\" title=\"{url}\"", url = s)
                };
                format!("<a href={href}{alt}>{{\"{body}\"}}</a>", href = href, alt = alt, body = from)
            }
            SmartLink::Image { img, to, alt, bind: _ } => {
                let href = match to {
                    None => String::new(),
                    Some(s) => format!(" src=\"{}\"", s)
                };
                let alt = match alt {
                    None => String::new(),
                    Some(s) => format!(" alt=\"{url}\" title=\"{url}\"", url = s)
                };
                format!("<img src={href}{alt}>{{\"{body}\"}}</a>", href = href, alt = alt, body = img)
            }
            SmartLink::Reciprocal => { unimplemented!() }
            SmartLink::Tag => { unimplemented!() }
            SmartLink::Reference => { unimplemented!() }
        }
    }
}


impl ToYew for &str {
    fn to_yew(&self) -> String {
        self.replace("\"", "\\\"")
            .replace("{", "{{")
            .replace("}", "}}")
    }
}

impl ToYew for &String {
    fn to_yew(&self) -> String {
        ToYew::to_yew(&self.as_str())
    }
}