package ru.forbion.f7cloud.feature.mail

import android.net.Uri

/** Shared HTML normalization and reader styles for mail message bodies. */
object MailBodyHtml {
    val READER_CSS = """
        html, body {
          margin: 0;
          padding: 0;
          overflow-x: hidden;
          word-wrap: break-word;
          overflow-wrap: anywhere;
        }
        body {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
          font-size: 16px;
          line-height: 1.45;
          color: #1a1a1a;
          padding: 8px;
        }
        body, p, div, span, td, th, li, blockquote {
          white-space: normal !important;
        }
        img, table, video {
          max-width: 100% !important;
          height: auto !important;
        }
        a:has(img) {
          pointer-events: none !important;
          cursor: default !important;
        }
        table {
          table-layout: fixed;
          width: 100%;
        }
        p {
          margin: 0 0 0.35em !important;
        }
        p:last-child {
          margin-bottom: 0 !important;
        }
        p:empty,
        p:has(br:only-child) {
          margin: 0 !important;
          line-height: 0 !important;
          font-size: 0 !important;
        }
        pre, code {
          white-space: pre-wrap !important;
          word-break: break-word;
        }
        blockquote,
        .quote,
        details.quoted-text,
        .gmail_quote,
        .gmail_extra,
        .moz-cite-prefix,
        #divRplyFwdMsg {
          margin: 2px 0 !important;
          margin-left: 0 !important;
          padding: 0 0 0 6px !important;
          border: none !important;
          border-left: 1px solid #70B62B !important;
          max-width: none !important;
        }
        blockquote blockquote,
        blockquote .quote,
        .quote blockquote,
        .quote .quote,
        details.quoted-text details.quoted-text {
          margin-left: 0 !important;
          padding-left: 6px !important;
        }
        blockquote [style*="margin-left"],
        blockquote [style*="padding-left"],
        .quote [style*="margin-left"],
        .quote [style*="padding-left"],
        .gmail_quote [style*="margin-left"],
        .gmail_quote [style*="padding-left"] {
          margin-left: 0 !important;
          padding-left: 0 !important;
        }
    """.trimIndent()

    private val EMPTY_PARAGRAPH = Regex(
        """<p[^>]*>(?:\s|&nbsp;|&#160;|&#xA0;|<br\s*/?>)*</p>""",
        RegexOption.IGNORE_CASE,
    )
    private val NBSP_RUN = Regex("""(?:&nbsp;|&#160;|&#xA0;|\u00A0){2,}""", RegexOption.IGNORE_CASE)
    private val SPACE_RUN = Regex(""" {2,}""")

    private val MAIL_PROXY_URL = Regex(
        """https?://[^"'\s<>)]+/apps/mail/proxy\?[^"'\s<>)]+""",
        RegexOption.IGNORE_CASE,
    )
    private val CID_REFERENCE = Regex("""cid:([^"'\s>)]+)""", RegexOption.IGNORE_CASE)

    fun normalizeForDisplay(html: String): String {
        var normalized = MailWebBranding.replaceInText(html)
        normalized = normalized.replace(EMPTY_PARAGRAPH, "")
        normalized = normalized.replace(NBSP_RUN, "&nbsp;")
        // Only collapse spaces between tags to avoid breaking preformatted text nodes.
        normalized = normalized.replace(Regex(">(\\s{2,})<")) { match ->
            ">" + match.groupValues[1].replace(SPACE_RUN, " ") + "<"
        }
        return normalized
    }

    /**
     * Rewrites image sources for mobile WebView:
     * - unwraps Nextcloud mail proxy URLs (proxy requires session cookies, not Basic auth)
     * - resolves cid: inline images to authenticated API attachment URLs
     */
    fun rewriteImageSources(
        html: String,
        messageId: Int,
        apiBase: String,
        attachments: List<MailAttachment>,
    ): String {
        if (html.isBlank()) return html
        var result = unwrapMailProxyUrls(html)
        if (messageId > 0 && result.contains("cid:", ignoreCase = true)) {
            result = rewriteCidReferences(result, messageId, apiBase, attachments)
        }
        return result
    }

    fun unwrapMailProxyUrls(html: String): String =
        MAIL_PROXY_URL.replace(html) { match -> unwrapProxyUrl(match.value) }

    fun unwrapProxyUrl(url: String): String {
        val normalized = url.replace("&amp;", "&")
        return runCatching {
            Uri.parse(normalized).getQueryParameter("src")?.takeIf { it.isNotBlank() }
        }.getOrNull() ?: url
    }

    private fun rewriteCidReferences(
        html: String,
        messageId: Int,
        apiBase: String,
        attachments: List<MailAttachment>,
    ): String {
        val byCid = attachments.mapNotNull { attachment ->
            attachment.cid
                ?.trim('<', '>')
                ?.takeIf { it.isNotBlank() }
                ?.let { it to attachment }
        }.toMap()
        val base = apiBase.trimEnd('/')
        return CID_REFERENCE.replace(html) { match ->
            val cid = match.groupValues[1].trim('<', '>')
            val attachment = byCid[cid]
            if (attachment != null) {
                "$base/messages/$messageId/attachment/${attachment.id}"
            } else {
                match.value
            }
        }
    }

    fun normalizePlainForDisplay(text: String): String =
        text.lines()
            .joinToString("\n") { line ->
                line.replace(SPACE_RUN, " ").trimEnd()
            }
            .trimEnd()

    fun formatPreviewText(raw: String): String {
        if (raw.isBlank()) return ""
        val withoutTags = raw.replace(Regex("<[^>]+>"), " ")
        val decoded = runCatching {
            android.text.Html.fromHtml(withoutTags, android.text.Html.FROM_HTML_MODE_LEGACY).toString()
        }.getOrDefault(withoutTags)
        return normalizePlainForDisplay(decoded).replace('\n', ' ')
    }
}
