//
//  LNWebViewController.swift
//  Lanu
//
//  Created by OneeChan on 2025/12/12.
//

import Foundation
import UIKit
import SnapKit
import WebKit
import Combine
import AutoCodable


class LNJumpWebViewConfig {
    var url: String
    var customTitle: String = ""
    var showNavigationBar = false
    var setSafeArea = false
    
    static func normalConfig(url: String) -> LNJumpWebViewConfig {
        let config = LNJumpWebViewConfig(url: url)
        config.showNavigationBar = true
        config.setSafeArea = true
        return config
    }
    
    init(url: String, title: String = "") {
        self.url = url
        customTitle = title
    }
    
    init(param: LNWebPageDeeplinkParams) {
        url = param.url
        showNavigationBar = param.header
        setSafeArea = param.safeArea
    }
}

extension UIView {
    func pushToWebView(_ config: LNJumpWebViewConfig) {
        if config.url.isDeeplink, let url = URL(string: config.url) {
            LNDeeplinkManager.shared.handleDeepLink(url)
            return
        }
        let vc = LNWebViewController(config: config)
        navigationController?.pushViewController(vc, animated: true)
    }
    
    func pushToWebView(_ param: LNWebPageDeeplinkParams) {
        let config = LNJumpWebViewConfig(param: param)
        let vc = LNWebViewController(config: config)
        navigationController?.pushViewController(vc, animated: true)
    }
}


class LNWebViewController: LNViewController {
    private let config: LNJumpWebViewConfig
    private var webView: WKWebView?
    
    init(config: LNJumpWebViewConfig) {
        self.config = config
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupViews()
        
        loadUrl()
    }
}

extension LNWebViewController {
    private func loadUrl() {
        guard let url = URL(string: config.url) else { return }
        
        webView?.load(URLRequest(url: url))
    }
}

extension LNWebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
                 decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void) {
        guard let url = navigationAction.request.url,
              let scheme = url.scheme else {
            decisionHandler(.allow) // 无 URL/Schema，允许默认行为
            return
        }
        
        guard scheme.lowercased() == LNDeeplinkUrls.appScheme else {
            decisionHandler(.allow)
            return
        }
        let fullPath = if let host = url.host {
            "\(host)\(url.path)"
        } else {
            url.path
        }
        if fullPath == LNDeeplinkUrls.web.closeWindow.deeplinkPath {
            navigationController?.popViewController(animated: true)
        } else if fullPath == LNDeeplinkUrls.web.userCancellation.deeplinkPath {
            LNAccountManager.shared.clean()
        } else {
            LNDeeplinkManager.shared.handleDeepLink(url)
        }
        
        decisionHandler(.cancel)
    }
}

extension LNWebViewController {
    private func setupViews() {
        if !config.customTitle.isEmpty {
            title = config.customTitle
        }
        showNavigationBar = config.showNavigationBar
        
        let webView = buildWebView()
        view.addSubview(webView)
        webView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            if config.showNavigationBar || !config.setSafeArea {
                make.top.equalToSuperview()
            } else if config.setSafeArea {
                make.top.equalToSuperview().offset(UIView.statusBarHeight)
            }
            if config.setSafeArea {
                make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)
            } else {
                make.bottom.equalToSuperview()
            }
        }
    }
    
    private func buildWebView() -> UIView {
        let webConfig = WKWebViewConfiguration()
        setupDefaultLocalStorage(webConfig)
        
        let webView = WKWebView(frame: .zero, configuration: webConfig)
        webView.navigationDelegate = self
#if DEBUG
        if #available(iOS 16.4, *) {
            webView.isInspectable = true
        }
#endif
        webView.scrollView.contentInsetAdjustmentBehavior = .never
        webView.scrollView.bounces = false
        
        setupDefaultCookie(webView)
        
        webView.publisher(for: \.title).removeDuplicates().sink
        { [weak self] webTitle in
            guard let self else { return }
            guard config.customTitle.isEmpty else { return }
            
            title = webTitle
        }.store(in: &cancellables)
        
        self.webView = webView
        
        return webView
    }
    
    private func setupDefaultLocalStorage(_ webConfig: WKWebViewConfiguration) {
        let tokenScript = WKUserScript(
            source: "window.localStorage.setItem('GAMI-web_auth_token', '\(LNAccountManager.shared.token)')",
            injectionTime: .atDocumentStart, forMainFrameOnly: true)
        webConfig.userContentController.addUserScript(tokenScript)
        
        let languageScript = WKUserScript(
            source: "window.localStorage.setItem('GAMI-web_app_locale', '\(LNAppConfig.shared.curLang.bundleName)')",
            injectionTime: .atDocumentStart, forMainFrameOnly: true)
        webConfig.userContentController.addUserScript(languageScript)
        
        var header: [String: Any] = [:]
        header["time"] = curTimeInMicro
        header["network"] = LNNetworkMonitor.curNetworkType.desc
        header["version"] = curBuildVersion
        header["api"] = 1
        header["channel"] = "appStore"
        header["platform"] = "2"
        header["device"] = curDeviceModelName
        header["app"] = curAppBundleIdentifier
        header["udid"] = curDeviceId
        header["token"] = LNAccountManager.shared.token
        if let jsonData = try? JSONSerialization.data(withJSONObject: header),
           let jsonStr = String(data: jsonData, encoding: .utf8) {
            let headerScript = WKUserScript(
                source: "javascript:window.GAMI_BRIDGE={'requestHeader': \(jsonStr), 'safeArea': \"\(UIView.statusBarHeight)|\(view.safeBottomInset)\"}",
                injectionTime: .atDocumentStart,
                forMainFrameOnly: true)
            webConfig.userContentController.addUserScript(headerScript)
        }
    }
    
    private func setupDefaultCookie(_ webView: WKWebView) {
        // 创建 Cookie
        if let tokenCookie = HTTPCookie(properties: [
            .domain: ".gami.vip",
            .path: "/",
            .name: "GAMI-cookie_auth_token",
            .value: LNAccountManager.shared.token,
            .secure: "TRUE",
            .expires: NSDate(timeIntervalSinceNow: 3600)
        ]) {
            webView.configuration.websiteDataStore.httpCookieStore.setCookie(tokenCookie)
        }
        if let languageCookie = HTTPCookie(properties: [
            .domain: ".gami.vip",
            .path: "/",
            .name: "GAMI-cookie_app_locale",
            .value: LNAppConfig.shared.curLang.bundleName,
            .secure: "TRUE",
            .expires: NSDate(timeIntervalSinceNow: 3600)
        ]) {
            webView.configuration.websiteDataStore.httpCookieStore.setCookie(languageCookie)
        }
        if let languageCookie = HTTPCookie(properties: [
            .domain: ".gami.vip",
            .path: "/",
            .name: "GAMI-cookie_safe_area",
            .value: "\(UIView.statusBarHeight)|\(view.safeBottomInset)",
            .secure: "TRUE",
            .expires: NSDate(timeIntervalSinceNow: 3600)
        ]) {
            webView.configuration.websiteDataStore.httpCookieStore.setCookie(languageCookie)
        }
    }
}
