package me.khodak.claudeusage

import android.annotation.SuppressLint
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.os.Bundle
import android.view.View
import android.webkit.*
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.khodak.claudeusage.data.PreferencesManager
import me.khodak.claudeusage.databinding.ActivityLoginBinding

class LoginActivity : AppCompatActivity() {

    private lateinit var binding: ActivityLoginBinding
    private lateinit var prefs: PreferencesManager
    private var loginHandled = false

    // JS injected before page scripts run — hides WebView fingerprints
    private val antiDetectionJs = """
        (function() {
            Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
            window.chrome = { runtime: {} };
            Object.defineProperty(navigator, 'plugins', { get: () => [1,2,3] });
            Object.defineProperty(navigator, 'languages', { get: () => ['en-US','en'] });
        })();
    """.trimIndent()

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityLoginBinding.inflate(layoutInflater)
        setContentView(binding.root)
        prefs = PreferencesManager(this)

        setupTabs()
        setupWebView()
        setupCookiePanel()
    }

    private fun setupTabs() {
        binding.tabBrowser.setOnClickListener {
            binding.panelBrowser.visibility = View.VISIBLE
            binding.panelCookie.visibility = View.GONE
            binding.tabBrowser.backgroundTintList = android.content.res.ColorStateList.valueOf(0xFFCC785C.toInt())
            binding.tabBrowser.setTextColor(0xFFFFFFFF.toInt())
            binding.tabCookie.backgroundTintList = android.content.res.ColorStateList.valueOf(0xFF2A2A2A.toInt())
            binding.tabCookie.setTextColor(0xFF888888.toInt())
        }
        binding.tabCookie.setOnClickListener {
            binding.panelBrowser.visibility = View.GONE
            binding.panelCookie.visibility = View.VISIBLE
            binding.tabCookie.backgroundTintList = android.content.res.ColorStateList.valueOf(0xFFCC785C.toInt())
            binding.tabCookie.setTextColor(0xFFFFFFFF.toInt())
            binding.tabBrowser.backgroundTintList = android.content.res.ColorStateList.valueOf(0xFF2A2A2A.toInt())
            binding.tabBrowser.setTextColor(0xFF888888.toInt())
        }
    }

    @SuppressLint("SetJavaScriptEnabled")
    private fun setupWebView() {
        CookieManager.getInstance().removeAllCookies(null)
        CookieManager.getInstance().flush()

        binding.btnDone.setOnClickListener { attemptCookieCapture(force = true) }

        with(binding.webView) {
            settings.apply {
                javaScriptEnabled = true
                domStorageEnabled = true
                databaseEnabled = false
                javaScriptCanOpenWindowsAutomatically = false
                setSupportMultipleWindows(false)
                // Standard Android Chrome UA — less suspicious than desktop
                userAgentString = "Mozilla/5.0 (Linux; Android 13; Pixel 7) " +
                    "AppleWebKit/537.36 (KHTML, like Gecko) " +
                    "Chrome/120.0.6099.230 Mobile Safari/537.36"
            }
            CookieManager.getInstance().setAcceptCookie(true)
            CookieManager.getInstance().setAcceptThirdPartyCookies(this, true)

            webViewClient = object : WebViewClient() {
                override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
                    val uri = request.url
                    val url = uri.toString()
                    // Keep blocking app-redirect schemes outright.
                    if (url.startsWith("market://") || url.startsWith("intent://")) return true
                    val scheme = uri.scheme?.lowercase()
                    // about:blank and data: URIs are used by the login page itself (e.g. blank
                    // bootstrap frames, inline images). They have no host to allow-list, so let them load.
                    if (scheme == "about" || scheme == "data") return false
                    // Host ALLOW-LIST: only navigate to claude.ai and its SSO/CDN providers.
                    // OAuth runs as full-page redirects in THIS WebView (multiple windows disabled,
                    // JS-opened windows disabled), so the list MUST include the Google/Apple SSO
                    // and Cloudflare challenge hosts or sign-in breaks. Anything else is blocked.
                    return !isHostAllowed(uri.host)
                }

                override fun onPageStarted(view: WebView, url: String, favicon: android.graphics.Bitmap?) {
                    // Inject before page scripts
                    view.evaluateJavascript(antiDetectionJs, null)
                }

                override fun onPageFinished(view: WebView, url: String) {
                    // Re-inject after page load
                    view.evaluateJavascript(antiDetectionJs, null)

                    if (url.contains("claude.ai")) {
                        binding.btnDone.visibility = View.VISIBLE
                    }
                    if (loginHandled) return
                    val onMain = url.startsWith("https://claude.ai") &&
                        !url.contains("/login") && !url.contains("/auth") &&
                        !url.contains("/sign") && !url.contains("/verify")
                    if (onMain) attemptCookieCapture(force = false)
                }
            }
            loadUrl("https://claude.ai/login")
        }
    }

    private fun setupCookiePanel() {
        binding.btnSaveCookie.setOnClickListener {
            val cookie = binding.etCookie.text.toString().trim()
            if (cookie.length < 10) {
                Toast.makeText(this, "Cookie too short — paste the full string", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            handleLoginSuccess(cookie)
        }
    }

    private fun attemptCookieCapture(force: Boolean) {
        if (loginHandled) return
        CookieManager.getInstance().flush()
        val cookies = CookieManager.getInstance().getCookie("https://claude.ai") ?: ""
        if (cookies.length > 10) {
            loginHandled = true
            handleLoginSuccess(cookies)
        } else if (force) {
            Toast.makeText(this, "No session found — finish logging in first, or use the Paste Cookie tab", Toast.LENGTH_LONG).show()
        }
    }

    private fun handleLoginSuccess(cookies: String) {
        prefs.saveCookies(cookies)
        prefs.saveSessionStart(System.currentTimeMillis())
        prefs.markTodayActive()
        Toast.makeText(this, "Signed in — loading usage…", Toast.LENGTH_SHORT).show()

        UsageUpdateWorker.triggerImmediateRefresh(this)
        UsageUpdateWorker.schedulePeriodicRefresh(this)

        lifecycleScope.launch(Dispatchers.IO) {
            try {
                val data = UsageRepository(prefs).fetchUsage()
                prefs.saveUsageData(data)
                val mgr = AppWidgetManager.getInstance(this@LoginActivity)
                val ids = mgr.getAppWidgetIds(ComponentName(this@LoginActivity, ClaudeUsageWidget::class.java))
                ids.forEach { id -> ClaudeUsageWidget.updateWidget(this@LoginActivity, mgr, id, data) }
            } catch (_: Exception) {}
        }

        setResult(RESULT_OK)
        finish()
    }

    override fun onBackPressed() {
        if (binding.panelBrowser.visibility == View.VISIBLE && binding.webView.canGoBack())
            binding.webView.goBack()
        else super.onBackPressed()
    }

    override fun onDestroy() {
        binding.webView.destroy()
        super.onDestroy()
    }

    /**
     * True if [host] belongs to an allowed domain (exact match or a subdomain via dot-suffix).
     * A null/blank host is never allowed. accounts.google.com, challenges.cloudflare.com, etc. are
     * covered by their parent-domain suffixes (google.com, cloudflare.com).
     */
    private fun isHostAllowed(host: String?): Boolean {
        if (host.isNullOrBlank()) return false
        val h = host.lowercase()
        return ALLOWED_DOMAINS.any { d -> h == d || h.endsWith(".$d") }
    }

    companion object {
        // WebView host allow-list. Login navigation is restricted to claude.ai and the SSO/CDN
        // hosts it redirects through. This MUST include the SSO providers (Google, Apple) and
        // Cloudflare challenge hosts — OAuth happens as same-WebView full-page redirects, so
        // dropping any of these breaks sign-in. Subdomains are matched by dot-suffix.
        private val ALLOWED_DOMAINS = listOf(
            "claude.ai",
            "anthropic.com",
            "google.com",            // covers accounts.google.com
            "gstatic.com",
            "googleusercontent.com",
            "googleapis.com",
            "apple.com",
            "icloud.com",
            "cloudflare.com",        // covers challenges.cloudflare.com
            "cloudflareinsights.com",
            "recaptcha.net"
        )
    }
}
