import UIKit
import WebKit
import Capacitor

public class WKWebViewController: UIViewController {
    
    // MARK: - Properties
    private var webView: WKWebView!
    private var toolbar: UIToolbar?
    private var options: WebViewOptions
    private var source: WKWebSource
    private var loadingView: UIView?
    
    // MARK: - Callbacks
    public var onUrlChange: ((String) -> Void)?
    public var onClose: ((String) -> Void)?
    public var onPageLoaded: (() -> Void)?
    public var onPageLoadError: (() -> Void)?
    public var onMessage: ((Any) -> Void)?
    
    // MARK: - Initialization
    public init(source: WKWebSource, options: WebViewOptions) {
        self.source = source
        self.options = options
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - Lifecycle
    public override func viewDidLoad() {
        super.viewDidLoad()
        setupWebView()
        setupToolbar()
        setupConstraints()
        loadContent()
    }
    
    public override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        webView?.stopLoading()
    }
    
    deinit {
        webView?.configuration.userContentController.removeScriptMessageHandler(forName: "mobileApp")
        webView?.stopLoading()
        webView?.removeFromSuperview()
    }
    
    // MARK: - Setup
    private func setupWebView() {
        let configuration = WKWebViewConfiguration()
        configuration.allowsInlineMediaPlayback = true
        configuration.mediaTypesRequiringUserActionForPlayback = []
        
        if options.isInspectable, #available(iOS 16.4, *) {
            configuration.isInspectable = true
        }
        
        webView = WKWebView(frame: .zero, configuration: configuration)
        webView.navigationDelegate = self
        webView.uiDelegate = self
        webView.translatesAutoresizingMaskIntoConstraints = false
        
        // 添加 JavaScript 消息处理
        configuration.userContentController.add(self, name: "mobileApp")
        
        view.addSubview(webView)
    }
    
    private func setupToolbar() {
        guard options.toolbarType != .blank else { return }
        
        toolbar = UIToolbar()
        toolbar?.translatesAutoresizingMaskIntoConstraints = false
        toolbar?.barTintColor = UIColor(hexString: options.toolbarColor) ?? .white
        toolbar?.isTranslucent = false
        
        updateToolbarItems()
        
        if let toolbar = toolbar {
            view.addSubview(toolbar)
        }
    }
    
    private func setupConstraints() {
        var constraints: [NSLayoutConstraint] = []
        
        if let toolbar = toolbar {
            constraints.append(contentsOf: [
                toolbar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                toolbar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                toolbar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                
                webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                webView.topAnchor.constraint(equalTo: toolbar.bottomAnchor),
                webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ])
        } else {
            constraints.append(contentsOf: [
                webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                webView.topAnchor.constraint(equalTo: view.topAnchor),
                webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ])
        }
        
        NSLayoutConstraint.activate(constraints)
    }
    
    private func updateToolbarItems() {
        guard let toolbar = toolbar else { return }
        
        var items: [UIBarButtonItem] = []
        
        switch options.toolbarType {
        case .navigation:
            items = createNavigationItems()
        case .activity:
            items = createActivityItems()
        case .default:
            items = createDefaultItems()
        case .blank:
            break
        }
        
        toolbar.setItems(items, animated: false)
    }
    
    private func createNavigationItems() -> [UIBarButtonItem] {
        let backButton = UIBarButtonItem(
            image: UIImage(systemName: "chevron.left"),
            style: .plain,
            target: self,
            action: #selector(backButtonTapped)
        )
        
        let forwardButton = UIBarButtonItem(
            image: UIImage(systemName: "chevron.right"),
            style: .plain,
            target: self,
            action: #selector(forwardButtonTapped)
        )
        
        let flexibleSpace = UIBarButtonItem(
            barButtonSystemItem: .flexibleSpace,
            target: nil,
            action: nil
        )
        
        let closeButton = UIBarButtonItem(
            barButtonSystemItem: .done,
            target: self,
            action: #selector(closeButtonTapped)
        )
        
        var items = [backButton, forwardButton, flexibleSpace]
        
        if options.showReloadButton {
            let reloadButton = UIBarButtonItem(
                barButtonSystemItem: .refresh,
                style: .plain,
                target: self,
                action: #selector(reloadButtonTapped)
            )
            items.append(reloadButton)
        }
        
        items.append(closeButton)
        return items
    }
    
    private func createActivityItems() -> [UIBarButtonItem] {
        let closeButton = UIBarButtonItem(
            barButtonSystemItem: .done,
            target: self,
            action: #selector(closeButtonTapped)
        )
        
        let flexibleSpace = UIBarButtonItem(
            barButtonSystemItem: .flexibleSpace,
            target: nil,
            action: nil
        )
        
        let titleItem = UIBarButtonItem(
            title: options.title,
            style: .plain,
            target: nil,
            action: nil
        )
        
        var items = [closeButton, flexibleSpace]
        
        if options.visibleTitle {
            items.append(titleItem)
            items.append(flexibleSpace)
        }
        
        if options.showReloadButton {
            let reloadButton = UIBarButtonItem(
                barButtonSystemItem: .refresh,
                style: .plain,
                target: self,
                action: #selector(reloadButtonTapped)
            )
            items.append(reloadButton)
        }
        
        return items
    }
    
    private func createDefaultItems() -> [UIBarButtonItem] {
        let closeButton = UIBarButtonItem(
            barButtonSystemItem: .done,
            target: self,
            action: #selector(closeButtonTapped)
        )
        
        let flexibleSpace = UIBarButtonItem(
            barButtonSystemItem: .flexibleSpace,
            target: nil,
            action: nil
        )
        
        let titleItem = UIBarButtonItem(
            title: options.title,
            style: .plain,
            target: nil,
            action: nil
        )
        
        var items = [closeButton, flexibleSpace]
        
        if options.visibleTitle {
            items.append(titleItem)
            items.append(flexibleSpace)
        }
        
        if options.showReloadButton {
            let reloadButton = UIBarButtonItem(
                barButtonSystemItem: .refresh,
                style: .plain,
                target: self,
                action: #selector(reloadButtonTapped)
            )
            items.append(reloadButton)
        }
        
        return items
    }
    
    // MARK: - Content Loading
    private func loadContent() {
        switch source {
        case .remote(let url):
            loadURL(url)
        case .file(let url, access: _):
            loadFileURL(url)
        case .string(let html, base: let baseURL):
            loadHTMLString(html, baseURL: baseURL)
        }
    }
    
    private func loadURL(_ url: URL) {
        var request = URLRequest(url: url)
        
        // 添加headers
        if !options.headers.isEmpty {
            for (key, value) in options.headers {
                request.setValue(value, forHTTPHeaderField: key)
            }
        }
        
        // 添加credentials
        if let credentials = options.credentials {
            let authString = "\(credentials.username):\(credentials.password)"
            if let authData = authString.data(using: .utf8) {
                let base64Auth = authData.base64EncodedString()
                request.setValue("Basic \(base64Auth)", forHTTPHeaderField: "Authorization")
            }
        }
        
        webView.load(request)
    }
    
    private func loadFileURL(_ url: URL) {
        webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
    }
    
    private func loadHTMLString(_ html: String, baseURL: URL?) {
        webView.loadHTMLString(html, baseURL: baseURL)
    }
    
    // MARK: - Actions
    @objc private func backButtonTapped() {
        if webView.canGoBack {
            webView.goBack()
        }
    }
    
    @objc private func forwardButtonTapped() {
        if webView.canGoForward {
            webView.goForward()
        }
    }
    
    @objc private func reloadButtonTapped() {
        webView.reload()
    }
    
    @objc private func closeButtonTapped() {
        if options.closeModal {
            let alert = UIAlertController(
                title: options.closeModalTitle,
                message: options.closeModalDescription,
                preferredStyle: .alert
            )
            
            alert.addAction(UIAlertAction(title: options.closeModalCancel, style: .cancel))
            alert.addAction(UIAlertAction(title: options.closeModalOk, style: .destructive) { [weak self] _ in
                self?.closeWebView()
            })
            
            present(alert, animated: true)
        } else {
            closeWebView()
        }
    }
    
    private func closeWebView() {
        onClose?(webView.url?.absoluteString ?? "")
        dismiss(animated: options.isAnimated)
    }
    
    // MARK: - JavaScript Interface
    private func injectJavaScriptInterface() {
        let script = """
            if (!window.mobileApp) {
                window.mobileApp = {
                    postMessage: function(message) {
                        window.webkit.messageHandlers.mobileApp.postMessage(message);
                    }
                };
            }
            
            if (!window.postMessageToJS) {
                window.postMessageToJS = function(detail) {
                    window.dispatchEvent(new CustomEvent('messageFromNative', { detail: detail }));
                };
            }
            
            if (!window.AIFF) {
                window.AIFF = {
                    postMessage: window.mobileApp.postMessage,
                    receiveMessage: function(callback) {
                        window.addEventListener('messageFromNative', callback);
                    }
                };
            }
        """
        
        webView.evaluateJavaScript(script) { result, error in
            if let error = error {
                print("JavaScript injection error: \(error)")
            }
        }
    }
    
    // MARK: - Public Methods
    public func postMessageToJS(_ detail: Any) {
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: ["detail": detail])
            let jsonString = String(data: jsonData, encoding: .utf8) ?? "{}"
            
            let script = "window.dispatchEvent(new CustomEvent('messageFromNative', \(jsonString)));"
            
            webView.evaluateJavaScript(script) { result, error in
                if let error = error {
                    print("Error sending message to JS: \(error)")
                }
            }
        } catch {
            print("Error serializing message: \(error)")
        }
    }
    
    public func executeScript(_ code: String) {
        webView.evaluateJavaScript(code) { result, error in
            if let error = error {
                print("Error executing script: \(error)")
            }
        }
    }
    
    public func setURL(_ url: String) {
        if let url = URL(string: url) {
            loadURL(url)
        }
    }
    
    public func reload() {
        webView.reload()
    }
}

// MARK: - WKNavigationDelegate
extension WKWebViewController: WKNavigationDelegate {
    
    public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        if let preShowScript = options.preShowScript, !preShowScript.isEmpty {
            executeScript(preShowScript)
        }
    }
    
    public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        onPageLoaded?()
        injectJavaScriptInterface()
        updateTitle()
        
        if options.isPresentAfterPageLoad {
            // 延迟显示逻辑
        }
    }
    
    public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        onPageLoadError?()
    }
    
    public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        
        guard let url = navigationAction.request.url else {
            decisionHandler(.cancel)
            return
        }
        
        // URL 变化事件
        onUrlChange?(url.absoluteString)
        
        // 处理非 HTTP/HTTPS 协议
        if !url.scheme?.hasPrefix("http") ?? true {
            if UIApplication.shared.canOpenURL(url) {
                UIApplication.shared.open(url)
                decisionHandler(.cancel)
                return
            }
        }
        
        decisionHandler(.allow)
    }
    
    public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        
        // SSL 错误处理
        if options.ignoreUntrustedSSLError, challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
            completionHandler(.useCredential, credential)
            return
        }
        
        // HTTP 认证
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic,
           let credentials = options.credentials {
            let credential = URLCredential(
                user: credentials.username,
                password: credentials.password,
                persistence: .forSession
            )
            completionHandler(.useCredential, credential)
            return
        }
        
        completionHandler(.performDefaultHandling, nil)
    }
}

// MARK: - WKUIDelegate
extension WKWebViewController: WKUIDelegate {
    
    public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in
            completionHandler()
        })
        present(alert, animated: true)
    }
    
    public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "取消", style: .cancel) { _ in
            completionHandler(false)
        })
        alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in
            completionHandler(true)
        })
        present(alert, animated: true)
    }
    
    public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        let alert = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)
        alert.addTextField { textField in
            textField.text = defaultText
        }
        alert.addAction(UIAlertAction(title: "取消", style: .cancel) { _ in
            completionHandler(nil)
        })
        alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in
            completionHandler(alert.textFields?.first?.text)
        })
        present(alert, animated: true)
    }
}

// MARK: - WKScriptMessageHandler
extension WKWebViewController: WKScriptMessageHandler {
    
    public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "mobileApp" {
            onMessage?(message.body)
        }
    }
}

// MARK: - Supporting Types
public enum WKWebSource: Equatable {
    case remote(URL)
    case file(URL, access: URL)
    case string(String, base: URL?)
    
    public var url: URL? {
        switch self {
        case .remote(let u): return u
        case .file(let u, access: _): return u
        default: return nil
        }
    }
}

public enum ToolbarType: String, CaseIterable {
    case activity = "activity"
    case navigation = "navigation"
    case blank = "blank"
    case `default` = ""
}

public struct WebViewOptions {
    public var title: String?
    public var toolbarType: ToolbarType
    public var showReloadButton: Bool
    public var closeModal: Bool
    public var closeModalTitle: String
    public var closeModalDescription: String
    public var closeModalOk: String
    public var closeModalCancel: String
    public var toolbarColor: String
    public var visibleTitle: Bool
    public var showArrow: Bool
    public var isAnimated: Bool
    public var isInspectable: Bool
    public var isPresentAfterPageLoad: Bool
    public var ignoreUntrustedSSLError: Bool
    public var preShowScript: String?
    public var headers: [String: String]
    public var credentials: Credentials?
    
    public init() {
        self.title = "新窗口"
        self.toolbarType = .default
        self.showReloadButton = false
        self.closeModal = false
        self.closeModalTitle = "关闭"
        self.closeModalDescription = "您确定要关闭此窗口吗？"
        self.closeModalOk = "关闭"
        self.closeModalCancel = "取消"
        self.toolbarColor = "#ffffff"
        self.visibleTitle = true
        self.showArrow = false
        self.isAnimated = true
        self.isInspectable = false
        self.isPresentAfterPageLoad = false
        self.ignoreUntrustedSSLError = false
        self.headers = [:]
    }
}

public struct Credentials {
    public let username: String
    public let password: String
    
    public init(username: String, password: String) {
        self.username = username
        self.password = password
    }
}

// MARK: - UIColor Extension
extension UIColor {
    convenience init?(hexString: String) {
        let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        var int = UInt64()
        
        guard Scanner(string: hex).scanHexInt64(&int) else {
            return nil
        }
        
        let a, r, g, b: UInt64
        switch hex.count {
        case 3: // RGB (12-bit)
            (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
        case 6: // RGB (24-bit)
            (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
        case 8: // ARGB (32-bit)
            (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
        default:
            return nil
        }
        
        self.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
    }
}