import CoreNFC
import NFCSDK

@objc(NFCManager)
public class NFCManager: NSObject, NFCTagReaderSessionDelegate {
    // 单例实例（改为实例属性，而非直接用 static 方法）
    static let instance = NFCManager()
    // NFCSDK 助手（改为实例属性）
    let helper = IOSNFCHelper()
    // NFC 会话（改为实例属性）
    var session: NFCTagReaderSession?
    // 控制状态（改为实例属性）
    var readyToStart = true
    var controlName = ""
    
    private override init() {
        super.init()
    }
    
    // MARK: - 对外暴露的 OC 调用方法（通过单例调用实例方法）
    @objc
    public static func startScan() {
        instance._startScan()
    }
    
    @objc
    public static func endScan() {
        instance._endScan()
    }
    
    @objc
    public static func endScan(errorMessage: String) {
        instance._endScan(errorMessage: errorMessage)
    }
    
    @objc
    public static func setLoopCb(cb: @escaping (String, Bool, Int) -> Bool) {
        instance._setLoopCb(cb: cb)
    }
    
    @objc
    public static func setFinishedCb(cb: @escaping () -> Void) {
        instance._setFinishedCb(cb: cb)
    }
    
    @objc
    public static func setChargingCb(cb: @escaping (String, Int) -> Void) {
        instance._setChargingCb(cb: cb)
    }
    
    @objc
    public static func setControllingCb(cb: @escaping (String, Int) -> Void) {
        instance._setControllingCb(cb: cb)
    }
    
    @objc
    public static func lock(password: String) {
        instance._lock(password: password)
    }
    
    @objc
    public static func unlock(password: String) {
        instance._unlock(password: password)
    }
    
    // MARK: - 实际的实例方法（核心逻辑）
    private func _startScan() {
        // 1. 检查设备是否支持 NFC
        guard NFCTagReaderSession.readingAvailable else {
            _endScan(errorMessage: "Device does not support NFC")
            return
        }
        
        if readyToStart {
            readyToStart = false
            // 2. 修复语法错误：移除末尾多余的逗号
            session = NFCTagReaderSession(
                pollingOption: [.iso14443],
                delegate: self,  // 这里必须传实例 self，而非静态的 self
                queue: nil
            )
            session?.alertMessage = "Hold your iPhone near the device"
            session?.begin()
        }
    }
    
    private func _endScan() {
        session?.invalidate()
        Task {
            try? await Task.sleep(nanoseconds: 2_000_000_000)
            readyToStart = true
        }
    }
    
    private func _endScan(errorMessage: String) {
        session?.invalidate(errorMessage: errorMessage)
        Task {
            try? await Task.sleep(nanoseconds: 2_000_000_000)
            readyToStart = true
        }
    }
    
    private func _setLoopCb(cb: @escaping (String, Bool, Int) -> Bool) {
        helper.setLoopCb { id, isNew, rssi in
            let isNew0 = isNew.boolValue
            let rssi0 = rssi?.intValue ?? 0
            self.session?.alertMessage = "Device detected"
            return KotlinBoolean(bool: cb(id, isNew0, rssi0))
        }
    }
    
    private func _setFinishedCb(cb: @escaping () -> Void) {
        helper.setFinishedCb(cb: {
            self._endScan()
            cb()
        })
    }
    
    private func _setChargingCb(cb: @escaping (String, Int) -> Void) {
        helper.setChargingCb { res, level in
            let level0 = level?.intValue ?? 0
            switch res {
            case "OK":
                self.session?.alertMessage = "Charging (\(level0)%)"
            case "UNAUTHORIZED":
                self._endScan(errorMessage: "Authentication failed")
            default:
                self._endScan(errorMessage: "NFC tag lost")
            }
            cb(res, level0)
        }
    }
    
    private func _setControllingCb(cb: @escaping (String, Int) -> Void) {
        helper.setControllingCb { res, progress in
            let progress0 = progress?.intValue ?? 0
            switch res {
            case "OK":
                if progress0 < 100 {
                    self.session?.alertMessage = "\(self.controlName) (\(progress0)%)"
                } else {
                    self.session?.alertMessage = "\(self.controlName) succeeded"
                }
            default:
                self._endScan(errorMessage: "\(self.controlName) failed")
            }
            cb(res, progress0)
        }
    }
    
    private func _lock(password: String) {
        controlName = "Locking"
        helper.lock(password: password)
    }
    
    private func _unlock(password: String) {
        controlName = "Unlocking"
        helper.unlock(password: password)
    }
    
    // MARK: - NFCTagReaderSessionDelegate 协议方法（必须是实例方法）
    // 1. 可选方法：会话激活时调用（非必选，但建议保留）
    public func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
        print("NFC Session Active")
    }
    
    // 2. 必选方法：会话失效/出错时调用
    public func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
        // 区分用户主动取消和真实错误
        if let nfcError = error as? NFCReaderError {
            if nfcError.code != .readerSessionInvalidationErrorUserCanceled {
                print("NFC Session Error: \(nfcError.localizedDescription)")
            }
        }
        _endScan()
    }
    
    // 3. 必选方法：检测到 NFC 标签时调用
    public func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [CoreNFC.NFCTag]) {
        guard let tag = tags.first else {
            _endScan(errorMessage: "No valid NFC tag detected")
            return
        }
        
        session.connect(to: tag) { [weak self] error in
            guard let self = self else { return } // 避免循环引用
            
            if let error = error {
                self._endScan(errorMessage: "NFC connection failed: \(error.localizedDescription)")
                return
            }
            
            switch tag {
            case .miFare(let miFareTag):
                self.helper.setTransceiver { data, resolve in
                    let length = Int(data.size)
                    var buffer = [UInt8](repeating: 0, count: length)
                    for i in 0..<length {
                        buffer[i] = UInt8(truncatingIfNeeded: data.get(index: Int32(i)))
                    }
                    let command = Data(buffer)
                    
                    miFareTag.sendMiFareCommand(commandPacket: command) { response, error in
                        if let error = error {
                            self._endScan(errorMessage: "NFC tag lost: \(error.localizedDescription)")
                            let _ = resolve(KotlinByteArray(size: 0))
                            return
                        }
                        
                        let byteArray = KotlinByteArray(size: Int32(response.count))
                        for (i, byte) in response.enumerated() {
                            byteArray.set(index: Int32(i), value: Int8(truncatingIfNeeded: byte))
                        }
                        let _ = resolve(byteArray)
                    }
                }
                
                Task {
                    do {
                        try await self.helper.process()
                    } catch {
                        print("process error: \(error.localizedDescription)")
                    }
                }
                
            default:
                self._endScan(errorMessage: "Not an NFC-A tag")
            }
        }
    }
}
