from flask import current_app, request, url_for
from flask_babel import gettext
from markupsafe import Markup, escape


def render_text_plain(_subtype, content, _path):
    return f'<div class="jwm-mail-body-text-plain"><pre>{escape(content)}</pre></div>\n'


def render_text_html(_subtype, _content, path):
    if path:
        url = url_for(
            "read",
            msgid=request.view_args["msgid"],
            format="raw",
            path=".".join(map(str, path)),
        )
    else:
        url = url_for("read", msgid=request.view_args["msgid"], format="raw")

    return f'<iframe src="{url}" class="jwm-mail-body-text-html" ></iframe>\n'


def render_image(subtype, content, _path):
    return f'<img src="data:image/{subtype};base64,{escape(content)}" />\n'


def render_multipart_alternative(_subtype, content, path):
    parts = content["parts"]
    T = "<div class=tabs><ul>\n"
    C = "<div class=jwm-mail-body-multipart-alternative-bodies>"
    init, *rest = reversed(parts)

    T += f"<li class=is-active data=0><a>{to_mime_type(init['head'])}</a></li>"

    C += "<div class=jwm-mail-body-multipart-alternative-body>\n"
    C += mime_render(
        *to_mime_types(init["head"]), init["body"], path + (len(parts) - 1,)
    )
    C += "</div>\n"

    for i, r in enumerate(rest, 1):
        T += f"<li data={i}><a>{to_mime_type(r['head'])}</a></li>\n"

        C += '<div class="jwm-mail-body-multipart-alternative-body is-hidden">\n'
        C += mime_render(
            *to_mime_types(r["head"]), r["body"], path + (len(parts) - 1 - i,)
        )
        C += "</div>\n"

    C += "</div>"
    T += "</ul></div>"
    script_url = url_for("static", filename="src/rendermail.js")
    return f'<script src="{script_url}"></script><div class="jwm-mail-body jwm-mail-body-multipart-alternative">\n{T}\n{C}\n</div>\n'


def render_multipart(_subtype, content, path):
    parts = content["parts"]
    R = '<div class="jwm-mail-body jwm-mail-body-multipart">\n'

    for i, p in enumerate(parts):
        R += "<div class=media><div class=media-content>\n"
        if (
            not p["head"]["content_disposition"]
            or p["head"]["content_disposition"].lower() == "none"
            or p["head"]["content_disposition"].lower() == "inline"
        ):
            R += mime_render(*to_mime_types(p["head"]), p["body"], path + (i,))
        elif p["head"]["content_disposition"].lower() == "attachment":
            link_text = gettext("Attachment {filename} of type {filetype}").format(
                filename=p["head"]["filename"], filetype=to_mime_type(p["head"])
            )

            ref_url = url_for(
                "read",
                msgid=request.view_args["msgid"],
                path=".".join(map(str, [*path, i])),
                format="raw",
            )

            R += "<p>"
            R += f'<a href="{ref_url}" download="{escape(p["head"]["filename"])}">\n'
            R += f"{escape(link_text)}</a>\n"
            R += "</p>\n"
        else:
            current_app.log.warning(
                "unknown Content-Disposition %s", p["head"]["content_disposition"]
            )
            R += f"<p>unknown Content-Disposition {p['head']['content_disposition']}</p>\n"

        R += "</div></div>\n"

    return R + "</div>\n"


def _format_header(category, value):
    R = ""

    if isinstance(value, list) and value:
        R += f"<dt>{escape(category)}</dt>\n"
        for v in value:
            value = (
                f'"{v["display_name"]}" <{v["address"]}>'
                if v["display_name"]
                else v["address"]
            )
            R += f"<dd>{escape(value)}<dd>\n"

    return R


def render_message(subtype, msg, path):
    if subtype != "rfc822":
        current_app.log.warning("unknown message mime-subtype %s", subtype)

    R = '<div class="jwm-mail">'

    R += '<dl class="jwm-mail-header">'
    R += f"<dt>{escape(gettext('Subject'))}</dt>"
    R += f"<dd>{escape(msg['head']['subject'])}</dd>\n"
    R += _format_header(gettext("From"), msg["head"].get("from"))
    R += _format_header(gettext("To"), msg["head"].get("to"))
    R += _format_header(gettext("CC"), msg["head"].get("cc"))
    R += _format_header(gettext("BCC"), msg["head"].get("bcc"))
    R += f"<dt>{escape(gettext('Date'))}</dt>"
    R += f"<dd>{escape(msg['head']['date'])}</dd>\n"
    R += f"<dt>{escape(gettext('Content-Type'))}</dt>"
    R += f"<dd>{to_mime_type(msg['head']['mime'])}</dd>\n"
    R += "</dl>\n"

    R += mime_render(*to_mime_types(msg["head"]["mime"]), msg["body"], path + (0,))

    return R + "</div>\n"


MIMERenderSubs = {
    ("text", "plain"): render_text_plain,
    ("text", "html"): render_text_html,
    ("multipart", "alternative"): render_multipart_alternative,
    "multipart": render_multipart,
    "message": render_message,
    "image": render_image,
}


def mime_render(maintype, subtype, content, path):
    renderer = MIMERenderSubs.get((maintype, subtype)) or MIMERenderSubs.get(maintype)

    if not renderer:
        typ = f"<code>{maintype}/{subtype}</code>"
        msg = gettext("Unsupported MIME type of {mime_type}.").format(mime_type=typ)
        return f'<p class="jwm-body-unsupported">{msg}</p>\n'

    return renderer(subtype, content, path)


def to_mime_type(mime):
    return escape(f"{mime['content_maintype']}/{mime['content_subtype']}".lower())


def to_mime_types(mime):
    return escape(mime["content_maintype"]), escape(mime["content_subtype"])


def format_mail(mail):
    return Markup(mime_render("message", "rfc822", mail, tuple()))