package ru.forbion.f7cloud.mobile

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Message
import android.view.ViewGroup
import android.webkit.CookieManager
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.delay
import okhttp3.OkHttpClient
import ru.forbion.f7cloud.core.designsystem.F7Colors
import ru.forbion.f7cloud.core.designsystem.F7PrimaryButton
import ru.forbion.f7cloud.core.designsystem.F7Theme
import ru.forbion.f7cloud.core.network.NetworkFactory
import ru.forbion.f7cloud.feature.files.OfficeEditorLaunch

class OfficeEditorActivity : ComponentActivity() {

    private var webViewRef: WebView? = null
    private var editorVisible by mutableStateOf(false)
    private var loadError by mutableStateOf<String?>(null)
    private var launch by mutableStateOf<OfficeEditorLaunch?>(null)

    @OptIn(ExperimentalMaterial3Api::class)
    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val initial = readLaunch() ?: run {
            finish()
            return
        }
        launch = initial
        bindUi(initial)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        val next = readLaunch() ?: return
        if (OfficeWebViewPool.sessionKey(next) != launch?.let { OfficeWebViewPool.sessionKey(it) }) {
            OfficeWebViewPool.dispose()
            webViewRef = null
        }
        launch = next
        editorVisible = false
        loadError = null
        loadDocument(next)
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @SuppressLint("SetJavaScriptEnabled")
    private fun bindUi(initial: OfficeEditorLaunch) {
        val httpClient = NetworkFactory.newAuthedClientForOffice(
            initial.username,
            initial.password,
            initial.trustAllCerts,
        )
        val authHosts = OfficeWebViewClient.buildAuthHosts(initial)
        val interceptPrefixes = OfficeWebViewClient.buildInterceptPrefixes(initial)

        setContent {
            F7Theme {
                val currentLaunch = launch
                if (currentLaunch == null) return@F7Theme

                LaunchedEffect(currentLaunch.url, editorVisible) {
                    if (editorVisible) return@LaunchedEffect
                    delay(LOAD_TIMEOUT_MS)
                    if (!editorVisible && loadError == null) {
                        loadError = "Редактор не ответил вовремя. Проверьте интернет и попробуйте снова."
                    }
                }

                Scaffold(
                    topBar = {
                        TopAppBar(
                            title = {
                                Text(
                                    text = currentLaunch.title,
                                    maxLines = 1,
                                    overflow = TextOverflow.Ellipsis,
                                )
                            },
                            navigationIcon = {
                                IconButton(onClick = { finish() }) {
                                    Text("←", style = MaterialTheme.typography.titleLarge)
                                }
                            },
                            colors = TopAppBarDefaults.topAppBarColors(
                                containerColor = F7Colors.Surface,
                                titleContentColor = F7Colors.TextPrimary,
                            ),
                        )
                    },
                    containerColor = F7Colors.Background,
                ) { padding ->
                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(padding)
                            .background(androidx.compose.ui.graphics.Color.White),
                    ) {
                        if (loadError != null) {
                            Column(
                                modifier = Modifier
                                    .fillMaxSize()
                                    .padding(24.dp),
                                verticalArrangement = Arrangement.Center,
                                horizontalAlignment = Alignment.CenterHorizontally,
                            ) {
                                Text(
                                    loadError!!,
                                    style = MaterialTheme.typography.bodyLarge,
                                    textAlign = TextAlign.Center,
                                    color = F7Colors.TextPrimary,
                                )
                                F7PrimaryButton(
                                    text = "Закрыть",
                                    onClick = { finish() },
                                    modifier = Modifier.padding(top = 16.dp),
                                )
                            }
                        } else {
                            OfficeWebView(
                                launch = currentLaunch,
                                httpClient = httpClient,
                                authHosts = authHosts,
                                interceptPrefixes = interceptPrefixes,
                                modifier = Modifier.fillMaxSize(),
                            )
                            if (!editorVisible) {
                                Box(
                                    modifier = Modifier
                                        .fillMaxSize()
                                        .background(androidx.compose.ui.graphics.Color.White),
                                    contentAlignment = Alignment.Center,
                                ) {
                                    Column(horizontalAlignment = Alignment.CenterHorizontally) {
                                        CircularProgressIndicator(color = F7Colors.Primary)
                                        Text(
                                            "Загрузка редактора…",
                                            modifier = Modifier.padding(top = 16.dp),
                                            style = MaterialTheme.typography.bodyMedium,
                                            color = F7Colors.TextSecondary,
                                        )
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    fun onCollaboraDocumentLoaded(webView: WebView?) {
        editorVisible = true
        loadError = null
        webView?.evaluateJavascript(HIDE_F7CLOUD_CHROME_JS, null)
    }

    private fun loadDocument(target: OfficeEditorLaunch) {
        val view = webViewRef ?: return
        val current = view.url?.trimEnd('/').orEmpty()
        val next = target.url.trimEnd('/')
        if (current == next) return
        editorVisible = false
        loadError = null
        view.loadUrl(target.url)
    }

    private fun readLaunch(): OfficeEditorLaunch? {
        val url = intent.getStringExtra(EXTRA_URL) ?: return null
        val title = intent.getStringExtra(EXTRA_TITLE).orEmpty()
        val username = intent.getStringExtra(EXTRA_USERNAME).orEmpty()
        val password = intent.getStringExtra(EXTRA_PASSWORD).orEmpty()
        val serverUrl = intent.getStringExtra(EXTRA_SERVER_URL).orEmpty()
        if (url.isBlank() || username.isBlank()) return null
        return OfficeEditorLaunch(
            url = url,
            title = title,
            username = username,
            password = password,
            trustAllCerts = intent.getBooleanExtra(EXTRA_TRUST_ALL_CERTS, false),
            serverUrl = serverUrl,
            collaboraBaseUrl = intent.getStringExtra(EXTRA_COLLABORA_URL).orEmpty(),
        )
    }

    @SuppressLint("SetJavaScriptEnabled")
    @Composable
    private fun OfficeWebView(
        launch: OfficeEditorLaunch,
        httpClient: OkHttpClient,
        authHosts: Set<String>,
        interceptPrefixes: List<String>,
        modifier: Modifier = Modifier,
    ) {
        AndroidView(
            modifier = modifier,
            factory = { context ->
                OfficeWebViewPool.obtain(context, launch) { webView ->
                    configureOfficeWebView(
                        webView = webView,
                        launch = launch,
                        httpClient = httpClient,
                        authHosts = authHosts,
                        interceptPrefixes = interceptPrefixes,
                    )
                }.also { webView ->
                    webViewRef = webView
                    webView.layoutParams = FrameLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT,
                    )
                    val current = webView.url?.trimEnd('/').orEmpty()
                    val target = launch.url.trimEnd('/')
                    if (current != target) {
                        webView.loadUrl(launch.url)
                    }
                }
            },
            update = { webView ->
                webViewRef = webView
            },
            onRelease = { webViewRef = null },
        )
    }

    @SuppressLint("SetJavaScriptEnabled")
    private fun configureOfficeWebView(
        webView: WebView,
        launch: OfficeEditorLaunch,
        httpClient: OkHttpClient,
        authHosts: Set<String>,
        interceptPrefixes: List<String>,
    ) {
        webView.setBackgroundColor(android.graphics.Color.WHITE)
        val cookieManager = CookieManager.getInstance()
        cookieManager.setAcceptCookie(true)
        cookieManager.setAcceptThirdPartyCookies(webView, true)
        webView.settings.apply {
            javaScriptEnabled = true
            domStorageEnabled = true
            @Suppress("DEPRECATION")
            databaseEnabled = true
            javaScriptCanOpenWindowsAutomatically = true
            setSupportMultipleWindows(true)
            loadWithOverviewMode = true
            useWideViewPort = true
            builtInZoomControls = true
            displayZoomControls = false
            mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
            cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
            mediaPlaybackRequiresUserGesture = false
            userAgentString = MOBILE_USER_AGENT
        }
        webView.removeJavascriptInterface("RichDocumentsMobileInterface")
        webView.addJavascriptInterface(
            RichDocumentsMobileBridge(this@OfficeEditorActivity) { webViewRef },
            "RichDocumentsMobileInterface",
        )
        webView.webChromeClient = object : WebChromeClient() {
            override fun onCreateWindow(
                view: WebView?,
                isDialog: Boolean,
                isUserGesture: Boolean,
                resultMsg: Message?,
            ): Boolean {
                val transport = resultMsg?.obj as? WebView.WebViewTransport ?: return false
                val popup = WebView(webView.context).apply {
                    applyOfficePopupSettings(launch, httpClient, authHosts, interceptPrefixes)
                }
                transport.webView = popup
                resultMsg.sendToTarget()
                return true
            }
        }
        webView.webViewClient = createClient(launch, httpClient, authHosts, interceptPrefixes)
    }

    @SuppressLint("SetJavaScriptEnabled")
    private fun WebView.applyOfficePopupSettings(
        launch: OfficeEditorLaunch,
        httpClient: OkHttpClient,
        authHosts: Set<String>,
        interceptPrefixes: List<String>,
    ) {
        settings.javaScriptEnabled = true
        settings.domStorageEnabled = true
        settings.setSupportMultipleWindows(true)
        settings.userAgentString = MOBILE_USER_AGENT
        webViewClient = createClient(launch, httpClient, authHosts, interceptPrefixes)
    }

    private fun createClient(
        launch: OfficeEditorLaunch,
        httpClient: OkHttpClient,
        authHosts: Set<String>,
        interceptPrefixes: List<String>,
    ): WebViewClient = OfficeWebViewClient(
        launch = launch,
        httpClient = httpClient,
        authHosts = authHosts,
        interceptPrefixes = interceptPrefixes,
        onMainFrameError = { msg ->
            runOnUiThread {
                if (!editorVisible) {
                    loadError = "Не удалось загрузить редактор: $msg"
                }
            }
        },
        onPageReady = { view ->
            runOnUiThread {
                view?.evaluateJavascript(HIDE_F7CLOUD_CHROME_JS, null)
            }
        },
    )

    override fun onDestroy() {
        OfficeWebViewPool.recycle(webViewRef)
        webViewRef = null
        super.onDestroy()
    }

    companion object {
        private const val EXTRA_URL = "url"
        private const val EXTRA_TITLE = "title"
        private const val EXTRA_USERNAME = "username"
        private const val EXTRA_PASSWORD = "password"
        private const val EXTRA_TRUST_ALL_CERTS = "trust_all_certs"
        private const val EXTRA_SERVER_URL = "server_url"
        private const val EXTRA_COLLABORA_URL = "collabora_url"

        private const val LOAD_TIMEOUT_MS = 90_000L

        const val MOBILE_USER_AGENT =
            "Mozilla/5.0 (Linux; Android 13; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) " +
                "Chrome/131.0.0.0 Mobile Safari/537.36"

        const val HIDE_F7CLOUD_CHROME_JS = """
            (function() {
              var hide = function(el) { if (el) { el.style.display = 'none'; el.remove(); } };
              hide(document.getElementById('loadingContainer'));
              hide(document.getElementById('proxyLoadingContainer'));
              hide(document.getElementById('header'));
              hide(document.getElementById('app-navigation'));
              hide(document.getElementById('app-navigation-vue'));
              hide(document.querySelector('#body-user'));
              hide(document.querySelector('footer'));
              var main = document.getElementById('content');
              if (main) { main.style.margin = '0'; main.style.padding = '0'; }
              document.documentElement.style.overflow = 'hidden';
              document.body.style.margin = '0';
              document.body.style.padding = '0';
              document.body.style.background = '#fff';
              var doc = document.getElementById('documents-content');
              if (doc) {
                doc.style.position = 'fixed';
                doc.style.top = '0';
                doc.style.left = '0';
                doc.style.right = '0';
                doc.style.bottom = '0';
                doc.style.width = '100%';
                doc.style.height = '100%';
                doc.style.zIndex = '99999';
                doc.style.background = '#fff';
              }
              var frame = document.getElementById('loleafletframe') || document.querySelector('iframe');
              if (frame) {
                frame.style.width = '100%';
                frame.style.height = '100%';
                frame.style.minHeight = '100vh';
                frame.style.border = 'none';
              }
            })();
        """

        fun intent(context: Context, launch: OfficeEditorLaunch): Intent =
            Intent(context, OfficeEditorActivity::class.java).apply {
                addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                putExtra(EXTRA_URL, launch.url)
                putExtra(EXTRA_TITLE, launch.title)
                putExtra(EXTRA_USERNAME, launch.username)
                putExtra(EXTRA_PASSWORD, launch.password)
                putExtra(EXTRA_TRUST_ALL_CERTS, launch.trustAllCerts)
                putExtra(EXTRA_SERVER_URL, launch.serverUrl)
                putExtra(EXTRA_COLLABORA_URL, launch.collaboraBaseUrl)
            }
    }
}
