import Foundation
import WebKit

/// WebView 预热专用实例持有者（容量 = 1）。
///
/// **该实例仅用于预热，永不复用到页面容器**。
///
/// iOS `WKWebView` 无 clear-history API：若把加载过 `warmup.html` 的实例复用到页面，
/// `warmup.html` 会残留在 `backForwardList` 中（返回键可退回 warmup 页），且无法清除。
/// 为杜绝该历史暂留问题，容器每次都新建独立 WKWebView（见 ``TencentQianWebViewController``），
/// 预热实例只在后台承担网络/进程预热职责。
///
/// 预热收益完全由共享底座承接（无需复用实例本身）：
/// - **进程复用**：共享 ``TencentQianWebViewShared/processPool``——预建实例已启动 WebContent 进程，
///   页面新建的 WKWebView 复用同一进程，省进程冷启动。
/// - **磁盘缓存复用**：`.default()` DataStore——`warmup.html` 与真实页同 host，其写入的磁盘缓存
///   （HTML/JS/CSS 等静态资源）可被后续真实页跨实例命中，省网络时间。
///
/// 档位行为：
/// - light：离屏预建空实例（触发 WebContent 进程启动 + 保活）。
/// - heavy：预建实例加载对应 `warmup.html`（L4 网络预热，写入共享磁盘缓存）。
///
/// - 所有 WKWebView 操作均在主线程执行。
/// - 内存告警时 ``release()`` 释放。
final class WebViewPool {

    static let shared = WebViewPool()

    /// 预热专用实例（不复用到页面）。
    private var pooled: WKWebView?
    private var enabled = true

    /// 内存告警触发释放后的回调（供上层重置去重状态，使后续 prewarm 可重新预热）。
    ///
    /// 仅在 ``onMemoryWarning()`` 释放路径调用；客户主动 ``release()`` / ``setEnabled(_:)`` 不触发。
    /// 由 `TencentQianWebViewPrewarmer` 设置为 `{ dedup.reset() }`。
    var onReleasedByMemoryWarning: (() -> Void)?

    private init() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(onMemoryWarning),
            name: UIApplication.didReceiveMemoryWarningNotification,
            object: nil
        )
    }

    func setEnabled(_ value: Bool) {
        enabled = value
        if !value { release() }
    }

    /// light：离屏预建空实例（触发 WebContent 进程启动 + 保活），按 UA 配置建。
    func preCreate(injectUserAgent: Bool, userAgentExtra: String) {
        guard enabled else { return }
        runOnMain { _ = self.ensureInstance(injectUserAgent: injectUserAgent, userAgentExtra: userAgentExtra) }
    }

    /// heavy：确保预热实例存在（按 UA 配置建）并加载 warmup.html（L4 网络预热，写入共享磁盘缓存）。
    ///
    /// UA 尽量与 `open()` config 保持一致，以便 warmup.html 请求写入的磁盘缓存能被真实页命中。
    func warm(warmupUrl: String, injectUserAgent: Bool, userAgentExtra: String) {
        guard enabled, !warmupUrl.isEmpty else { return }
        runOnMain {
            guard let wv = self.ensureInstance(injectUserAgent: injectUserAgent, userAgentExtra: userAgentExtra),
                  let u = URL(string: warmupUrl) else { return }
            wv.load(URLRequest(url: u))
        }
    }

    /// 释放预热实例。
    func release() {
        runOnMain {
            self.pooled?.stopLoading()
            self.pooled?.loadHTMLString("", baseURL: nil)
            self.pooled = nil
        }
    }

    @objc private func onMemoryWarning() {
        // 预热实例不复用到页面（天然"不被借出"），直接释放不打断签署；
        // 释放后回调上层重置去重状态，使后续 prewarm 可重新预热。
        release()
        onReleasedByMemoryWarning?()
    }

    private func ensureInstance(injectUserAgent: Bool, userAgentExtra: String) -> WKWebView? {
        if pooled == nil {
            let conf = WKConfigurationFactory.makeConfiguration(
                injectUserAgent: injectUserAgent, userAgentExtra: userAgentExtra)
            pooled = WKWebView(frame: .zero, configuration: conf)
        }
        return pooled
    }

    private func runOnMain(_ block: @escaping () -> Void) {
        if Thread.isMainThread {
            block()
        } else {
            DispatchQueue.main.async(execute: block)
        }
    }
}
