//
//  ConfigSetting.swift
//  MpAccDemo
//

import UIKit
import MpAccSDK

extension ConfigSetting {
    private struct DEF {
        static let config_cache_data_key = "acc_demo_configs_key"
        static let groupId: String = "group.yunxiao.acc"
    }
    private static var userDefault = UserDefaults.standard //(suiteName: DEF.groupId)!
    private static func loadFromUserDefault() -> ConfigSetting {
        guard let data = userDefault.data(forKey: DEF.config_cache_data_key) else {
            return ConfigSetting()
        }
        
        guard let configModel = try? JSONDecoder().decode(ConfigSetting.self, from: data) else {
            return ConfigSetting()
        }
        return configModel
    }
    
    static func save() {
        shared.save()
    }
    func save() {
        guard let data = try? JSONEncoder().encode(self) else {
            return
        }
        ConfigSetting.userDefault.set(data, forKey: DEF.config_cache_data_key)
    }
    static func reset() {
        shared = ConfigSetting()
        shared.save()
    }
}

class ConfigRegisterSetting: Codable {
    var dataKey: String
    var deviceId: String
    init(dataKey: String, deviceId: String) {
        self.dataKey = dataKey
        self.deviceId = deviceId
    }
}

class ConfigSetting: NSObject, Codable {
    static var shared = ConfigSetting.loadFromUserDefault()
    
    var displayRollingLog = true
    
    // MARK: 日志设置
    var useLogPlugin: Bool = false
    var logLevel: LogLevel = .INFO
    
    // MARK: 注册参数
    var publicMode: Bool = true
    // 客户运行时 或 编译时 可修改 dataKey 和 deviceId
    var registerSetting = ConfigRegisterSetting(dataKey: "xxxxxx", deviceId: "xxxxxx")
    
    /// 加速节点，包含ipList+port，默认ipList为空数组，port为-1
//    var node: AccNode = AccNode(ipList: [], port: -1)
    /// 是否使用注册接口的node
    var autoNode: Bool = true
    
    var port: Int = 443
    // 逗号分割
    var ipv4sStr: String = "43.140.248.252"
    /// 加速模式   1：聚合     2：双发       3:rtc
    var accMode: Int = 2
    /// 回调间隔时间
    var pingInterval: Int = 1
    /// 拥塞算法
    var congrestionMode: MpCongrestionMode = .BBR
    /// 是否加密
    var encryption: Bool = true
    /// TCP直连
    var tcpDirect: Bool = false
    /// UDP直连
    var udpDirect: Bool = false
    ///
    var udpTimeout: Int = -1
    /// 连接最长超时时间，超过不再重连，单位：秒
    var maxReconnectTimeout: Int = 0
    /// 加速规则
    var accRules: [AccRule] = []
    /// 最大容忍时间阈值（ms）
//    var maxDelayTime: Int = 460
    /**
     *  链路优先级
     *  key:  0：mobile 1：wifi  priority.put(0,64) 设置type=0（mobile）的链路优先级是64
     *  value: 优先级为数字0-255， 数字越低优先级越高，默认64。当优先级数字>=128时，表示该链路为备份链路。
     */
//    var priority: [Int:Int] = [:]
    var wifiPriority: Int = 64
    var mobilePriority: Int = 64
    
    // MARK: 私有云(VPN & SOCKS)
    /// 密钥ID
    var keyID: String = "1221268485"
    /// 签名字符串
    var ciphertext: String = "050E2zxsG6BUveRvqAX6QBhd09CCVmKZuEQ6MRngbXPD8NnoZWunc79isj1UYLgujhnlZejHaCFXUi8S5iE5BjAIPQ=="
    //// 数字签名
    var signature: String = "Mgwpj3jdQbaqqdwDpnzYcNq2rs84RkAs+aPf+jUt6Mu553pC77L5WXpKU6JVfE29AcGbc7QPPR2Na/mZXVQkAXEYhd8IzjKwvKrQF4d3MY9/o/sz6Z9hKgFCaY7L6NG87+1lQ8OO6yRdarYpVBvN03z+BeU2freL4+PfCKuB9Co="
    
    /// maxRetryTimes
    var maxRetryTimes: Int = -1
    
    /// 启动加速所需网络条件，默认无条件
//    @objc public var networkConditions: NetworkConditions = .MUST_NONE
    var needNetworkConditions: Bool = false
    var needWiFiAvailable: Bool = false
    var needSIMAvailable: Bool = false
    var needMobileDataAvailable: Bool = false
    
    /// 设置是否保活
    var keepAlive: Bool = false
    
    // MARK: SOCKS5 字段
    /// socks代理端口号，默认 3000
    var socksProxyPort: Int = 3000
    /// socks5代理预设用户名
    @objc public var socksUsername: String? = nil
    /// socks5代理预设密码
    @objc public var socksPassword: String? = nil
    
    // MARK: 测速参数
    /// 公有云是否使用自定义测速地址
    var useAddr: Bool = false
    /// 测速地址（私有云设置）
    var addr: String = ""
    /// 滑动窗口测量时间 （ms）
    var time: Int = 30000
    /// 时延阈值
    var rtt: Int = 90
    /// 丢包率阈值
    var loss: Int = 5
    /// 抖动阈值
    var jitter: Int = 15
    /// 快启动窗口时间
    var quickTime: Int = 10000
    /// 快启动时延阈值
    var quickRtt: Int = 100
    /// 测量回调频率
    var interval: Int = 1000
    /// 设置延迟提醒时间，单位毫秒
    var delayRemindTime: Int = 10 * 1000
    
    /// 设置ping包超时时间，单位：ms
    var pingTimeout: Int = 1000
    /// 设置禁用快速检测, true 禁用  false：不禁用
    var disableQuickDetect: Bool = false
    
    /// 是否使用加强测速
    var enhanced: Bool = false
    /// 设置逃生附件选项, var additionalOptions: MpAdditionalOptions? = nil
    
    /// 加速链路连续【packetLossCount】失联
    var enablePacketLossEscape: Bool = false
    var packetLossEscape: MpAdditionalOptions.PacketLossEscape = .init(packetLossCount: 6)
    
    /// 加速链路连续【maxRttCount】ping值大于等于【rttThreshold】ms；
    var enableMaxRttEscape: Bool = false
    var maxRttEscape: MpAdditionalOptions.MaxRttEscape = .init(maxRttCount: 9, rttThreshold: 480)
    
    /// 加速链路【detectWindowTime】平均ping值大于主链路【rttDiffThreshold】%，并且acc平均时延大于【accBenchmarkRtt】ms；
    var enableRttExceptionEscape: Bool = false
    var rttExceptionEscape: MpAdditionalOptions.RttExceptionEscape = .init(detectWindowTime: 1000 * 50, accBenchmarkRtt: 80, rttDiffThreshold: 23)
    
    // 加速链路【detectWindowTime】内平均时延大于主链路【rttDiffRate】%，且抖动大于主链路【jitterRate】%，建议关闭加速
    var enableStopAccRemind: Bool = false
    var stopAccRemind: MpAdditionalOptions.StopAccRemind = .init(detectWindowTime: 5 * 1000 * 60, rttDiffRate: 0, jitterRate: 0)
}

extension ConfigSetting {
    static func getAccConfig() -> AccConfig {
        let setting = self.shared
        
        let config = AccConfig()
        /// 加速节点，包含ipList+port，默认ipList为空数组，port为-1
        if setting.autoNode == false || setting.publicMode == false {
            config.node.ipList = setting.ipv4sStr.split(separator: ",").map { String($0) }
            config.node.port = setting.port
        }
        /// 加速模式   1：聚合     2：双发        3:rtc
        config.accMode = AccMode(rawValue: setting.accMode)!
        /// 回调间隔时间
        config.pingInterval = setting.pingInterval
        /// 拥塞算法
        config.congrestionMode = setting.congrestionMode
        /// 是否加密
        config.encryption = setting.encryption
        ///
        config.udpTimeout = setting.udpTimeout
        /// 连接最长超时时间，超过不再重连，单位：秒
        config.maxReconnectTimeout = setting.maxReconnectTimeout
        /// 加速规则
        config.accRules = [
            AccRule(priority: 64, dstIPCIDR: "101.35.26.179/32", dstPortRange: "", proto: "", mode: setting.accMode)
        ]
        /// 最大容忍时间阈值（ms）
//        config.maxDelayTime = setting.maxDelayTime
        /**
         *  链路优先级
         *  key:  0：mobile 1：wifi  priority.put(0,64) 设置type=0（mobile）的链路优先级是64
         *  value: 优先级为数字0-255， 数字越低优先级越高，默认64。当优先级数字>=128时，表示该链路为备份链路。
         */
        config.priority = [
            0 : setting.mobilePriority,
            1 : setting.wifiPriority,
        ]
        
        if setting.needNetworkConditions {
            var conditions = [NetworkConditions]()
            if setting.needWiFiAvailable {
                conditions.append(.MUST_WIFI_ACTIVE)
            }
            if setting.needSIMAvailable {
                conditions.append(.MUST_SIM_CARD_READY)
            }
            if setting.needMobileDataAvailable {
                conditions.append(.MUST_MOBILE_DATA_ENABLE)
            }
            config.networkConditions = .combine(conditions)
        }
        
        // MARK: 私有云(VPN & SOCKS)
        if setting.publicMode == false {
            // 密钥ID
            config.setString(setting.keyID, forKey: AccConfig.KEY_SECRET_KEY_ID)
            // 签名字符串
            config.setString(setting.ciphertext, forKey: AccConfig.KEY_CIPHERTEXT)
            // 数字签名
            config.setString(setting.signature, forKey: AccConfig.KEY_SIGNTURE)
        }
        
        if setting.maxRetryTimes > -1 {
            config.setInt(setting.maxRetryTimes, forKey: AccConfig.KEY_MAX_RETRY_TIMES)
        }
        
//        // MARK: VPN通用字段
//        /// 设置vpn是否保活
//        config.keepAlive = setting.keepAlive
//        /// TCP直连
//        config.tcpDirect = setting.tcpDirect
//        /// UDP直连
//        config.udpDirect = setting.udpDirect
        
        // MARK: SOCKS5 字段
        /// socks代理端口号，默认 3000
        config.socksProxyPort = setting.socksProxyPort
        config.socksUsername = setting.socksUsername
        config.socksPassword = setting.socksPassword
        return config
    }
    
    static func getMeasureConfig() -> MpMeasureConfig {
        let setting = self.shared
        let config = MpMeasureConfig()
        if !setting.publicMode || setting.useAddr {
            /// 测速地址（私有云设置）
            config.addr = setting.addr
        }
        /// 滑动窗口测量时间 （ms）
        config.time = setting.time
        /// 时延阈值
        config.rtt = setting.rtt
        /// 丢包率阈值
        config.loss = setting.loss
        /// 抖动阈值
        config.jitter = setting.jitter
        /// 快启动窗口时间
        config.quickTime = setting.quickTime
        /// 快启动时延阈值
        config.quickRtt = setting.quickRtt
        /// 测量回调频率
        config.interval = setting.interval
        /// 加速模式
        config.mode = AccMode(rawValue: setting.accMode)!
        /// 设置延迟提醒时间，单位毫秒
        config.delayRemindTime = setting.delayRemindTime
        /// 设置ping包超时时间，单位：ms
        config.pingTimeout = setting.pingTimeout
        /// 设置禁用快速检测, true 禁用  false：不禁用
        config.disableQuickDetect = setting.disableQuickDetect
        /// 设置逃生附件选项
        if setting.enhanced {
            let additionalOptions = MpAdditionalOptions()
            if setting.enablePacketLossEscape {
                additionalOptions.packetLossEscape = setting.packetLossEscape
            }
            if setting.enableMaxRttEscape {
                additionalOptions.maxRttEscape = setting.maxRttEscape
            }
            if setting.enableRttExceptionEscape {
                additionalOptions.rttExceptionEscape = setting.rttExceptionEscape
            }
            if setting.enableStopAccRemind {
                additionalOptions.stopAccRemind = setting.stopAccRemind
            }
            config.additionalOptions = additionalOptions
        }
        return config
    }
    
    static func getRegisterParam() -> ConfigRegisterSetting {
        return self.shared.registerSetting
    }
}
