//
//  VPNManager.swift
//  sdlan
//
//  Created by 安礼成 on 2024/1/17.
//

import Foundation
import NetworkExtension
import SwiftUI
import Observation

// vpn管理类
@Observable
class VPNManager {
    static let shared = VPNManager()
    
    private var manager: NETunnelProviderManager?
    private var statusObserver: NSObjectProtocol?
    
    var vpnStatus: VPNStatus = .disconnected
    
    enum VPNStatus {
        case connected
        case disconnected
    }
    
    private init() {
        
    }
    
    // 开启vpn
    func enableVpn(options: [String : NSObject]) async throws {
        NSLog("enable vpn with options: \(options)")
        let manager = try await loadAndCreateProviderManager()
        try await manager.loadFromPreferences()
        self.manager = manager
        
        self.addVPNStatusObserver(manager)
        try manager.connection.startVPNTunnel(options: options)
    }
    
    // 关闭vpn
    func disableVpn() async throws {
        guard let manager = self.manager else {
            return
        }
        
        try await manager.loadFromPreferences()
        manager.connection.stopVPNTunnel()
    }
    
    // MARK: - Private Methods
    
    // 监控系统VPN的状态的变化
    private func addVPNStatusObserver(_ manager: NETunnelProviderManager) {
        if let statusObserver {
            NotificationCenter.default.removeObserver(statusObserver)
            self.statusObserver = nil
        }
        
        self.statusObserver = NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: manager.connection, queue: .main) {[weak self] _ in
            NSLog("status channge: \(manager.connection.status)")
            switch manager.connection.status {
            case .invalid, .disconnected, .disconnecting:
                self?.vpnStatus = .disconnected
            case .connecting, .connected, .reasserting:
                self?.vpnStatus = .connected
            @unknown default:
                self?.vpnStatus = .disconnected
            }
        }
    }
    
    // MARK: - Private Methods
    
    // 加载或者创建相关的配置
    private func loadAndCreateProviderManager() async throws -> NETunnelProviderManager {
        let managers = try await NETunnelProviderManager.loadAllFromPreferences()
        
        let manager = managers.first ?? NETunnelProviderManager()
        manager.localizedDescription = "punchnetmac"
        manager.isEnabled = true
        
        // 设置相关参数，在PacketTunnel中可以用
        let protocolConfiguration = NETunnelProviderProtocol()
        protocolConfiguration.serverAddress = "punchnetmac"
        protocolConfiguration.providerConfiguration = [String:AnyObject]()
        protocolConfiguration.providerBundleIdentifier = "com.jihe.punchnetmac.tun"
        manager.protocolConfiguration = protocolConfiguration
        manager.isOnDemandEnabled = false
        
        manager.isEnabled = true
        
        try await manager.saveToPreferences()
        
        return manager
    }
    
    deinit {
        if let statusObserver {
            NotificationCenter.default.removeObserver(statusObserver)
        }
    }
    
}
