import CoreBluetooth
import Foundation
#if canImport(React)
import React
#else
import RCTBridgeModule
import RCTEventEmitter
#endif

/// Bluetooth printer discovery (BLE only for iOS)
/// Based on react-native-bluetooth-escpos-printer logic
@objc(BluetoothDiscovery)
class BluetoothDiscovery: NSObject {

    // Event constants (compatible with old lib)
    static let EVENT_DEVICE_ALREADY_PAIRED = "EVENT_DEVICE_ALREADY_PAIRED"
    static let EVENT_DEVICE_FOUND = "EVENT_DEVICE_FOUND"
    static let EVENT_DEVICE_DISCOVER_DONE = "EVENT_DEVICE_DISCOVER_DONE"
    static let EVENT_BLUETOOTH_NOT_SUPPORT = "EVENT_BLUETOOTH_NOT_SUPPORT"

    private var centralManager: CBCentralManager?
    private var foundDevices: NSMutableDictionary = [:]
    private var scanTimer: Timer?
    private var isScanning = false
    private var eventEmitter: RCTEventEmitter?
    private var connectedPeripheral: CBPeripheral?
    private var pairedDevices: [[String: Any]] = []
    private var isInitialized = false

    init(eventEmitter: RCTEventEmitter? = nil) {
        self.eventEmitter = eventEmitter
        super.init()

        print("[Native:iOS] BluetoothDiscovery.init - SUCCESS: EventEmitter=\(eventEmitter != nil)")

        // Initialize central manager on main queue with options to not show power alert
        centralManager = CBCentralManager(
            delegate: self,
            queue: DispatchQueue.main,
            options: [CBCentralManagerOptionShowPowerAlertKey: false]
        )
    }

    /**
     * Scan devices - compatible with react-native-bluetooth-escpos-printer
     */
    @objc func scanDevices() -> [String: Any] {
        guard let central = centralManager else {
            emitRNEvent(BluetoothDiscovery.EVENT_BLUETOOTH_NOT_SUPPORT, nil)
            return ["success": false, "error": "Bluetooth manager not initialized"]
        }

        // Stop any existing scan
        if central.isScanning {
            central.stopScan()
        }

        isScanning = true
        foundDevices.removeAllObjects()
        pairedDevices = []

        // Add current connected device if any (treated as paired)
        if let connected = connectedPeripheral {
            let uuid = connected.identifier.uuidString
            let name = connected.name ?? ""

            let deviceInfo: [String: Any] = [
                "address": uuid,
                "name": name,
                "deviceType": "ble", // iOS connected devices are always BLE
                "isSupported": true
            ]

            pairedDevices.append(deviceInfo)
            foundDevices[uuid] = connected

            // Emit as paired device
            if let jsonData = try? JSONSerialization.data(
                withJSONObject: pairedDevices, options: []),
                let jsonString = String(data: jsonData, encoding: .utf8)
            {
                print("[Native:iOS] BluetoothDiscovery.scanDevices - PROCESS: Emitting \(pairedDevices.count) paired devices")
                let params: [String: Any] = ["devices": jsonString]
                emitRNEvent(BluetoothDiscovery.EVENT_DEVICE_ALREADY_PAIRED, params)
            }

            // Also emit as found
            emitDeviceFound(deviceInfo)
        }

        // Start scanning for all peripherals (no service filter)
        print("[Native:iOS] BluetoothDiscovery.scanDevices - START: Scanning for peripherals")
        central.scanForPeripherals(
            withServices: nil,
            options: [CBCentralManagerScanOptionAllowDuplicatesKey: false]
        )

        // Set timeout (10 seconds for testing, can change to 30 later)
        let scanTimeoutInterval: TimeInterval = 10.0

        scanTimer?.invalidate()
        scanTimer = Timer.scheduledTimer(
            timeInterval: scanTimeoutInterval,
            target: self,
            selector: #selector(handleScanTimeout),
            userInfo: nil,
            repeats: false
        )

        // Also use DispatchQueue as backup
        DispatchQueue.main.asyncAfter(deadline: .now() + scanTimeoutInterval) { [weak self] in
            if self?.isScanning == true {
                print("[Native:iOS] BluetoothDiscovery.scanDevices - PROCESS: Timeout via DispatchQueue")
                self?.stopScan()
            }
        }

        print("[Native:iOS] BluetoothDiscovery.scanDevices - PROCESS: Timer set for \(scanTimeoutInterval)s")

        return ["success": true]
    }

    /**
     * Check if Bluetooth is enabled
     */
    @objc func isBluetoothEnabled() -> Bool {
        return centralManager?.state == .poweredOn
    }

    /**
     * Scan timeout handler
     */
    @objc private func handleScanTimeout() {
        print("[Native:iOS] BluetoothDiscovery.handleScanTimeout - PROCESS: Timeout reached")
        stopScan()
    }

    /**
     * Stop scan
     */
    @objc func stopScan() {
        print("[Native:iOS] BluetoothDiscovery.stopScan - START")

        // Check if already stopped
        guard isScanning else {
            print("[Native:iOS] BluetoothDiscovery.stopScan - PROCESS: Already stopped")
            return
        }

        scanTimer?.invalidate()
        scanTimer = nil

        if let central = centralManager, central.isScanning {
            central.stopScan()
            print("[Native:iOS] BluetoothDiscovery.stopScan - SUCCESS")
        }

        isScanning = false

        // Send discovered devices
        var foundArray: [[String: Any]] = []

        for (_, peripheral) in foundDevices {
            if let peripheral = peripheral as? CBPeripheral {
                let deviceInfo: [String: Any] = [
                    "address": peripheral.identifier.uuidString,
                    "name": peripheral.name ?? "Unknown Device",
                    "deviceType": "ble", // iOS only supports BLE
                    "isSupported": true  // BLE devices are supported
                ]

                // Check if connected (treated as paired)
                if peripheral.state != .connected {
                    foundArray.append(deviceInfo)
                }
            }
        }

        // Convert to JSON strings
        let pairedJson =
            (try? JSONSerialization.data(withJSONObject: pairedDevices, options: [])).flatMap {
                String(data: $0, encoding: .utf8)
            } ?? "[]"
        let foundJson =
            (try? JSONSerialization.data(withJSONObject: foundArray, options: [])).flatMap {
                String(data: $0, encoding: .utf8)
            } ?? "[]"

        print(
            "[BluetoothDiscovery] Emitting DISCOVER_DONE with paired: \(pairedDevices.count), found: \(foundArray.count)"
        )

        // Emit old lib compatible event
        let params: [String: Any] = [
            "paired": pairedJson,
            "found": foundJson,
        ]
        emitRNEvent(BluetoothDiscovery.EVENT_DEVICE_DISCOVER_DONE, params)
    }

    /**
     * Handle discovered peripheral
     */
    private func handlePeripheralDiscovered(_ peripheral: CBPeripheral) {
        let uuid = peripheral.identifier.uuidString
        let name = peripheral.name ?? ""

        // Store peripheral
        foundDevices[uuid] = peripheral

        // Create device info
        let deviceInfo: [String: Any] = [
            "address": uuid,
            "name": name.isEmpty ? "Unknown Device" : name,
            "deviceType": "ble",
            "isSupported": true  // All BLE devices are supported on iOS
        ]

        // Emit device found
        emitDeviceFound(deviceInfo)
    }

    /**
     * Emit device found event (original format)
     */
    private func emitDeviceFound(_ device: [String: Any]) {
        // Emit device found event
        let event: [String: Any] = ["device": device]
        emitRNEvent(BluetoothDiscovery.EVENT_DEVICE_FOUND, event)
    }

    /**
     * Emit RN event
     */
    private func emitRNEvent(_ eventName: String, _ params: [String: Any]?) {
        print("[Native:iOS] BluetoothDiscovery.emitRNEvent - PROCESS: \(eventName) with params: \(params ?? [:])")
        if let emitter = eventEmitter {
            emitter.sendEvent(withName: eventName, body: params)
        } else {
            print("[Native:iOS] BluetoothDiscovery.emitRNEvent - WARN: eventEmitter is nil")
        }
    }
}

// MARK: - CBCentralManagerDelegate

extension BluetoothDiscovery: CBCentralManagerDelegate {

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        // Mark as initialized after first state update
        isInitialized = true

        switch central.state {
        case .poweredOn:
            // Ready to scan
            break
        case .poweredOff:
            stopScan()
        case .unauthorized:
            stopScan()
        case .unsupported:
            emitRNEvent(BluetoothDiscovery.EVENT_BLUETOOTH_NOT_SUPPORT, nil)
            stopScan()
        default:
            break
        }
    }

    func centralManager(
        _ central: CBCentralManager,
        didDiscover peripheral: CBPeripheral,
        advertisementData: [String: Any],
        rssi RSSI: NSNumber
    ) {
        print(
            "[BluetoothDiscovery] Discovered peripheral: \(peripheral.name ?? "Unknown") (\(peripheral.identifier.uuidString))"
        )
        handlePeripheralDiscovered(peripheral)
    }
}
