package ru.forbion.f7cloud.feature.mail

import android.annotation.SuppressLint
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

class MailRichTextEditorController {
    internal var webView: WebView? = null
    private var ready = false
    private val pending = mutableListOf<() -> Unit>()

    fun exec(command: String, value: String? = null) {
        val script = if (value == null) {
            "document.execCommand('$command', false, null);"
        } else {
            "document.execCommand('$command', false, ${jsString(value)});"
        }
        runWhenReady { webView?.evaluateJavascript(script, null) }
    }

    fun focus() {
        runWhenReady {
            webView?.evaluateJavascript("document.getElementById('editor').focus();", null)
        }
    }

    fun setHtml(html: String) {
        if (html.isBlank()) return
        val encoded = java.net.URLEncoder.encode(html, Charsets.UTF_8.name())
            .replace("'", "\\'")
        runWhenReady {
            webView?.evaluateJavascript(
                "document.getElementById('editor').innerHTML = decodeURIComponent('$encoded');",
                null,
            )
        }
    }

    fun insertHtml(html: String) {
        if (html.isBlank()) return
        val encoded = java.net.URLEncoder.encode(html, Charsets.UTF_8.name())
            .replace("'", "\\'")
        runWhenReady {
            webView?.evaluateJavascript(
                """
                (function() {
                  var html = decodeURIComponent('$encoded');
                  var editor = document.getElementById('editor');
                  var sel = window.getSelection();
                  if (!sel || sel.rangeCount === 0) {
                    editor.innerHTML += html;
                    return;
                  }
                  var range = sel.getRangeAt(0);
                  range.deleteContents();
                  var template = document.createElement('template');
                  template.innerHTML = html;
                  range.insertNode(template.content);
                })();
                """.trimIndent(),
                null,
            )
        }
    }

    suspend fun html(): String = query("document.getElementById('editor').innerHTML")

    suspend fun plainText(): String = query("document.getElementById('editor').innerText")

    internal fun markReady() {
        ready = true
        val actions = pending.toList()
        pending.clear()
        actions.forEach { it() }
    }

    private fun runWhenReady(action: () -> Unit) {
        if (ready) action() else pending += action
    }

    private suspend fun query(script: String): String = suspendCancellableCoroutine { cont ->
        runWhenReady {
            webView?.evaluateJavascript(script) { value ->
                cont.resume(value?.trim('"')?.replace("\\n", "\n")?.replace("\\\"", "\"") ?: "")
            }
        }
    }

    private fun jsString(value: String): String =
        "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'"
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MailRichTextEditor(
    modifier: Modifier = Modifier,
    controller: MailRichTextEditorController = remember { MailRichTextEditorController() },
) {
    val html = remember {
        """
        <!DOCTYPE html>
        <html>
        <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
        <style>
          html, body { margin: 0; padding: 0; height: 100%; background: #fff; }
          #editor {
            min-height: 100%;
            box-sizing: border-box;
            padding: 12px;
            outline: none;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            font-size: 16px;
            line-height: 1.45;
            color: #151515;
            word-break: break-word;
          }
        </style>
        </head>
        <body><div id="editor" contenteditable="true"></div></body>
        </html>
        """.trimIndent()
    }
    AndroidView(
        modifier = modifier,
        factory = { context ->
            WebView(context).apply {
                settings.javaScriptEnabled = true
                settings.domStorageEnabled = true
                setBackgroundColor(0xFFFFFFFF.toInt())
                addJavascriptInterface(
                    object {
                        @JavascriptInterface
                        fun onReady() {
                            post { controller.markReady() }
                        }
                    },
                    "AndroidEditor",
                )
                webViewClient = object : android.webkit.WebViewClient() {
                    override fun onPageFinished(view: WebView?, url: String?) {
                        evaluateJavascript("AndroidEditor.onReady();", null)
                    }
                }
                controller.webView = this
                loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)
            }
        },
        onRelease = {
            controller.webView = null
        },
    )
}
