//
//  PacketTunnelProvider.swift
//  punchnet
//
//  Created by 安礼成 on 2025/8/3.
//

import Foundation
import NetworkExtension

enum TunnelError: Error {
    case invalidConfiguration
    case invalidContext
}

class PacketTunnelProvider: NEPacketTunnelProvider {
    private var runtimeEnv: SDLRuntimeEnvironment?
    
    override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
        // 如果当前在运行状态，不允许重复请求
        guard self.runtimeEnv == nil else {
            completionHandler(TunnelError.invalidContext)
            return
        }
        
        guard let options, let config = SDLConfiguration.parse(options: options) else {
            completionHandler(TunnelError.invalidConfiguration)
            return
        }
        
        if self.runtimeEnv == nil {
            let rsaCipher = try! CCRSACipher(keySize: 1024)
            self.runtimeEnv = SDLRuntimeEnvironment(config: config, rsaCipher: rsaCipher, provider: self)
            self.runtimeEnv?.run()
        }
        
        self.runtimeEnv?.submitCommand(command: .start(completion: { err in
            completionHandler(err)
        }))
    }

    override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
        // Add code here to start the process of stopping the tunnel.
        self.runtimeEnv?.submitCommand(command: .stop(completion: {
            completionHandler()
        }))
    }

    override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
        // Add code here to handle the message.
        Task {
            do {
                let message = try AppRequest(serializedBytes: messageData)
                let replyData = try await self.handleAppRequest(message: message)
                completionHandler?(replyData)
            } catch let err {
                var reply = TunnelResponse()
                reply.code = 1
                reply.message = err.localizedDescription

                let errorReplyData = try? reply.serializedData()
                completionHandler?(errorReplyData)
            }
        }
    }

    override func sleep(completionHandler: @escaping () -> Void) {
        // Add code here to get ready to sleep.
        guard let runtimeEnv else {
            completionHandler()
            return
        }

        runtimeEnv.submitCommand(command: .stop(completion: {
            SDLLogger.log("[PacketTunnelProvider] sleep")
            completionHandler()
        }))
    }

    override func wake() {
        SDLLogger.log("[PacketTunnelProvider] wake up!!!!!!!")
        // Add code here to wake up.
        // 重新启动
        self.runtimeEnv?.submitCommand(command: .start(completion: { err in
            SDLLogger.log("[PacketTunnelProvider] wakeup and try start")
        }))
    }

    private func handleAppRequest(message: AppRequest) async throws -> Data? {
        guard let contextActor = self.runtimeEnv?.getContextActor() else {
            throw TunnelError.invalidContext
        }
        
        switch message.command {
        case .changeExitNode(let changeExitNode):
            let exitNodeIp = changeExitNode.ip
            do {
                try await contextActor.updateExitNode(exitNodeIp: exitNodeIp)
                var reply = TunnelResponse()
                reply.code = 0
                reply.message = "操作成功"
                return try reply.serializedData()
                
            } catch let err {
                var reply = TunnelResponse()
                reply.code = 1
                reply.message = err.localizedDescription
                
                return try reply.serializedData()
            }
        case .none:
            var reply = TunnelResponse()
            reply.code = 1
            reply.message = "无效请求"
            return try reply.serializedData()
        }
    }

}
