package ru.forbion.f7cloud.feature.mail

import android.annotation.SuppressLint
import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import ru.forbion.f7cloud.core.auth.AuthSession
import java.util.concurrent.TimeUnit

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MailMessageBodyView(
    session: AuthSession,
    messageId: Int,
    html: String,
    attachments: List<MailAttachment>,
    client: OkHttpClient,
    modifier: Modifier = Modifier,
) {
    val baseUrl = "${session.serverUrl.trimEnd('/')}/"
    val apiBase = "${session.serverUrl.trimEnd('/')}/index.php/apps/mail/api"
    val serverPrefix = remember(session.serverUrl) { session.serverUrl.trimEnd('/') }
    val externalClient = remember {
        OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }
    val bodyHtml = remember(html, messageId, apiBase, attachments) {
        MailBodyHtml.rewriteImageSources(
            html = MailBodyHtml.normalizeForDisplay(html),
            messageId = messageId,
            apiBase = apiBase,
            attachments = attachments,
        )
    }
    val wrapped = remember(bodyHtml, baseUrl) {
        """
        <!DOCTYPE html>
        <html>
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <style>${MailBodyHtml.READER_CSS}</style>
        </head>
        <body>$bodyHtml</body>
        </html>
        """.trimIndent()
    }

    AndroidView(
        modifier = modifier,
        factory = { context ->
            WebView(context).apply {
                layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                )
                settings.javaScriptEnabled = false
                settings.domStorageEnabled = false
                settings.loadsImagesAutomatically = true
                settings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
                // Вписывать письмо по ширине экрана: уважать viewport width=device-width
                // и масштабировать широкие письма (таблицы Битрикс/рассылок) в обзорный вид,
                // иначе WebView раскладывает по ~980px и контент уезжает за правый край.
                settings.useWideViewPort = true
                settings.loadWithOverviewMode = true
                settings.setSupportZoom(true)
                settings.builtInZoomControls = true
                settings.displayZoomControls = false
                isVerticalScrollBarEnabled = true
                isNestedScrollingEnabled = true
                setBackgroundColor(0x00000000)
                webViewClient = object : WebViewClient() {
                    override fun shouldInterceptRequest(
                        view: WebView?,
                        request: WebResourceRequest,
                    ): WebResourceResponse? {
                        val url = request.url?.toString() ?: return null
                        if (url.contains("/apps/mail/proxy", ignoreCase = true)) {
                            val directUrl = MailBodyHtml.unwrapProxyUrl(url)
                            if (directUrl != url) {
                                return fetchExternalImage(externalClient, directUrl)
                            }
                        }
                        if (!url.startsWith(serverPrefix, ignoreCase = true)) {
                            return null
                        }
                        if (!isServerMailResource(url)) {
                            return null
                        }
                        return fetchAuthedResource(client, url)
                    }
                }
            }
        },
        update = { webView ->
            webView.onResume()
            webView.resumeTimers()
            val loadedId = webView.tag as? Int
            if (loadedId != messageId) {
                webView.tag = messageId
                webView.loadDataWithBaseURL(baseUrl, wrapped, "text/html", "UTF-8", null)
            }
        },
        onRelease = { webView ->
            runCatching {
                webView.stopLoading()
                webView.onPause()
                webView.pauseTimers()
                webView.loadUrl("about:blank")
                webView.webViewClient = WebViewClient()
                (webView.parent as? ViewGroup)?.removeView(webView)
                webView.destroy()
            }
        },
    )
}

private fun isServerMailResource(url: String): Boolean =
    url.contains("/apps/mail/", ignoreCase = true)

private fun fetchAuthedResource(client: OkHttpClient, url: String): WebResourceResponse? =
    runCatching {
        val httpRequest = Request.Builder()
            .url(url)
            .header("OCS-APIRequest", "true")
            .build()
        client.newCall(httpRequest).execute().use(::toWebResourceResponse)
    }.getOrNull()

private fun fetchExternalImage(client: OkHttpClient, url: String): WebResourceResponse? =
    runCatching {
        val httpRequest = Request.Builder().url(url).build()
        client.newCall(httpRequest).execute().use(::toWebResourceResponse)
    }.getOrNull()

private fun toWebResourceResponse(response: Response): WebResourceResponse? {
    if (!response.isSuccessful || response.body == null) return null
    val body = response.body!!
    val contentType = body.contentType()
    val mimeType = contentType?.let { "${it.type}/${it.subtype}" } ?: "application/octet-stream"
    val encoding = when {
        mimeType.startsWith("image/") -> null
        mimeType.startsWith("video/") -> null
        mimeType.startsWith("audio/") -> null
        mimeType == "application/octet-stream" -> null
        else -> contentType?.charset()?.name() ?: "utf-8"
    }
    return WebResourceResponse(mimeType, encoding, body.byteStream())
}
