// VpnManager.swift — 主 App 侧 NETunnelProviderManager 封装（M3 PoC 实现）
//
// 职责：
//   1. loadAllFromPreferences / saveToPreferences — 首次安装时建立 VPN 配置条目
//   2. start / stop — 通过 NETunnelProviderSession 驱动 PacketTunnel extension
//   3. sendProviderMessage — 透传 IPC 消息到 PacketTunnelProvider.handleAppMessage
//   4. NEVPNStatus 订阅 → VpnStatusStreamHandler.shared 推送到 Dart 侧
//
// AppDelegate 持有本类单例，在 MethodChannel handler 中调用其方法。
//
// 红线词检查（⚠️ 产品文案不得出现：VPN / 翻墙 / 科学上网 / 突破封锁 / 自由穿越 /
//   Go anywhere）：localizedDescription 使用「Pangolin 加速」口径。

import Foundation
import NetworkExtension

// ── 流处理器（Flutter EventChannel stream handlers）───────────────

/// status 流：推送 "off" / "connecting" / "on" / "error" 字符串
class VpnStatusStreamHandler: NSObject, FlutterStreamHandler {
    static let shared = VpnStatusStreamHandler()
    private(set) var eventSink: FlutterEventSink?

    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        eventSink = events
        return nil
    }

    func onCancel(withArguments arguments: Any?) -> FlutterError? {
        eventSink = nil
        return nil
    }

    func push(_ status: String) {
        DispatchQueue.main.async { self.eventSink?(status) }
    }
}

/// stats 流：推送 [String: Any] 字典，字段同 vpn_bridge.dart VpnStatsEvent schema
class VpnStatsStreamHandler: NSObject, FlutterStreamHandler {
    static let shared = VpnStatsStreamHandler()
    private(set) var eventSink: FlutterEventSink?

    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        eventSink = events
        return nil
    }

    func onCancel(withArguments arguments: Any?) -> FlutterError? {
        eventSink = nil
        return nil
    }

    func push(_ stats: [String: Any]) {
        DispatchQueue.main.async { self.eventSink?(stats) }
    }
}

// ── VPN 管理器 ────────────────────────────────────────────────────

class VpnManager: NSObject {

    static let shared = VpnManager()

    private var tunnelManager: NETunnelProviderManager?

    // Bundle ID 与 PacketTunnel target PRODUCT_BUNDLE_IDENTIFIER 保持同步
    private let extensionBundleId = "com.pangolin.pangolinVpn.PacketTunnel"
    // App Group：与 PacketTunnel extension 共享 UserDefaults 容器
    private let appGroup = "group.com.pangolin.pangolinVpn"

    private var statusObserver: NSObjectProtocol?

    private override init() {
        super.init()
        subscribeToVpnStatus()
    }

    // ── 偏好设置加载与保存 ─────────────────────────────────────

    /// 从系统偏好加载已存在的 VPN 配置（首次为空列表）。
    /// 必须在调用 start() 前完成。
    func loadFromPreferences(completion: @escaping (Error?) -> Void) {
        NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
            guard let self = self else { return }
            if let error = error {
                completion(error)
                return
            }
            self.tunnelManager = managers?.first(where: {
                ($0.protocolConfiguration as? NETunnelProviderProtocol)?
                    .providerBundleIdentifier == self.extensionBundleId
            }) ?? NETunnelProviderManager()
            completion(nil)
        }
    }

    /// 创建或更新 VPN 配置条目（首次安装时调用一次）。
    func saveConfiguration(serverAddress: String = "pangolin", completion: @escaping (Error?) -> Void) {
        let manager = tunnelManager ?? NETunnelProviderManager()
        let proto = NETunnelProviderProtocol()
        proto.providerBundleIdentifier = extensionBundleId
        proto.serverAddress = serverAddress
        manager.protocolConfiguration = proto
        // ⚠️ 红线词规范：localizedDescription 用「加速」口径，不得出现 VPN/翻墙 等词。
        manager.localizedDescription = "Pangolin 加速"
        manager.isEnabled = true
        manager.saveToPreferences { [weak self] error in
            if error == nil { self?.tunnelManager = manager }
            completion(error)
        }
    }

    // ── 隧道控制 ──────────────────────────────────────────────

    /// 启动 VPN 隧道（通过 NETunnelProviderSession）。
    /// [configJson]: sing-box 配置 JSON，作为 options 传入 PacketTunnelProvider.startTunnel。
    func start(configJson: String, completion: @escaping (Error?) -> Void) {
        guard let manager = tunnelManager else {
            completion(makeError("VpnManager: tunnelManager not loaded. Call loadFromPreferences first."))
            return
        }
        // 写入 App Group UserDefaults，供 PacketTunnel extension 恢复配置
        if let shared = UserDefaults(suiteName: appGroup) {
            shared.set(configJson, forKey: "lastConfigJson")
        }
        do {
            let options: [String: NSObject] = ["config": configJson as NSString]
            try manager.connection.startVPNTunnel(options: options)
            completion(nil)
        } catch {
            completion(error)
        }
    }

    /// 停止 VPN 隧道。
    func stop() {
        tunnelManager?.connection.stopVPNTunnel()
    }

    /// 当前连接状态字符串（供 getStatus MethodChannel 方法使用）。
    var statusString: String {
        switch tunnelManager?.connection.status ?? .invalid {
        case .invalid, .disconnected:  return "off"
        case .connecting:              return "connecting"
        case .connected:               return "on"
        case .disconnecting:           return "connecting"
        case .reasserting:             return "connecting"
        @unknown default:              return "error"
        }
    }

    // ── IPC 消息通道 ──────────────────────────────────────────

    /// 向 PacketTunnelProvider.handleAppMessage 发送消息。
    func sendProviderMessage(_ data: Data, responseHandler: ((Data?, Error?) -> Void)?) {
        guard let session = tunnelManager?.connection as? NETunnelProviderSession else {
            responseHandler?(nil, makeError("VpnManager: no active NETunnelProviderSession"))
            return
        }
        do {
            try session.sendProviderMessage(data) { responseData in
                responseHandler?(responseData, nil)
            }
        } catch {
            responseHandler?(nil, error)
        }
    }

    // ── NEVPNStatus 订阅 ──────────────────────────────────────

    private func subscribeToVpnStatus() {
        statusObserver = NotificationCenter.default.addObserver(
            forName: NSNotification.Name.NEVPNStatusDidChange,
            object: nil,
            queue: .main
        ) { [weak self] _ in
            guard let self = self else { return }
            let s = self.statusString
            VpnStatusStreamHandler.shared.push(s)
        }
    }

    deinit {
        if let obs = statusObserver {
            NotificationCenter.default.removeObserver(obs)
        }
    }

    // ── 工具 ─────────────────────────────────────────────────

    private func makeError(_ message: String) -> NSError {
        NSError(domain: "VpnManager", code: -1, userInfo: [NSLocalizedDescriptionKey: message])
    }
}
