import CoreBluetooth
// SPDX-License-Identifier: MIT
import Foundation
import React

/**
 * React Native Thermal Printer Module for iOS
 * Simplified API with automatic connection management
 */
@objc(RNThermalPrinter)
class RNThermalPrinter: RCTEventEmitter {

    // Module instances
    private var bluetoothDiscovery: BluetoothDiscovery?
    private let connectionTester = ConnectionTester()
    private let printingModule = PrintingModule()
    private var hasListeners = false

    // MARK: - React Native Setup

    @objc override static func requiresMainQueueSetup() -> Bool {
        return true
    }

    override func startObserving() {
        hasListeners = true
    }

    override func stopObserving() {
        hasListeners = false
    }

    override func sendEvent(withName name: String!, body: Any!) {
        if hasListeners {
            super.sendEvent(withName: name, body: body)
        }
    }

    override func supportedEvents() -> [String]! {
        return [
            "EVENT_DEVICE_ALREADY_PAIRED",
            "EVENT_DEVICE_FOUND",
            "EVENT_DEVICE_DISCOVER_DONE",
            "EVENT_CONNECTION_STATE_CHANGED",
            "EVENT_BLUETOOTH_NOT_SUPPORT"
        ]
    }

    // MARK: - Discovery APIs

    /**
     * Scan Bluetooth devices
     * Returns paired and nearby devices
     */
    @objc(scanBluetoothDevices:rejecter:)
    func scanBluetoothDevices(
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock
    ) {
        if bluetoothDiscovery == nil {
            bluetoothDiscovery = BluetoothDiscovery(eventEmitter: self)
        }

        let result = bluetoothDiscovery?.scanDevices() ?? ["success": false, "error": "Failed to initialize"]
        resolve(result)
    }

    /**
     * Stop scanning for devices
     */
    @objc(stopScanDevices:rejecter:)
    func stopScanDevices(
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock
    ) {
        bluetoothDiscovery?.stopScan()
        resolve(true)
    }

    // MARK: - NEW SIMPLIFIED APIs

    /**
     * Test printer connection
     * Just checks if printer exists and is reachable
     * @param address Format: "bt:IDENTIFIER", "lan:IP:PORT", or "ble:UUID"
     * @return {success: boolean, deviceName?: string, error?: {code, message}}
     */
    @objc(testConnection:resolver:rejecter:)
    func testConnection(
        _ address: String,
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock
    ) {
        print("[Native:iOS] RNThermalPrinterModule.testConnection - START: \(address)")

        connectionTester.testPrinter(address: address, timeout: 5.0) { result in
            let resultDict = self.connectionTester.testResultToDictionary(result)
            resolve(resultDict)
        }
    }

    /**
     * Print data with automatic connection management
     * @param address Printer address
     * @param data Raw byte array
     * @param options {keepAlive?: boolean, timeout?: number}
     * @return {success: boolean, error?: {code, message, step}}
     */
    @objc(printRaw:data:options:resolver:rejecter:)
    func printRaw(
        _ address: String,
        data: [Int],
        options: [String: Any]?,
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock
    ) {
        print("[Native:iOS] RNThermalPrinterModule.printRaw - START: address=\(address), dataSize=\(data.count)")

        // Convert array to Data
        let bytes = Data(data.map { UInt8($0 & 0xFF) })

        // Parse options
        let keepAlive = options?["keepAlive"] as? Bool ?? false
        let timeoutSec = (options?["timeout"] as? Double ?? 10000) / 1000 // Convert ms to seconds

        // Execute print job
        Task {
            let result = await printingModule.printRaw(
                address: address,
                data: bytes,
                keepAlive: keepAlive,
                timeoutSec: timeoutSec
            )

            DispatchQueue.main.async {
                resolve(result.toDictionary())
            }
        }
    }

    /**
     * Print image from file path with automatic connection
     * @param address Printer address
     * @param imagePath Path to image file (now using file path like Android)
     * @param options {widthPx?: number, keepAlive?: boolean, timeout?: number, isCutPaper?: boolean}
     */
    @objc(printImage:imagePath:options:resolver:rejecter:)
    func printImage(
        _ address: String,
        imagePath: String,
        options: [String: Any]?,
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock
    ) {
        print("[Native:iOS] RNThermalPrinterModule.printImage - START: \(address)")
        print("[Native:iOS] RNThermalPrinterModule.printImage - PATH: \(imagePath)")

        // Parse options (simplified, matching Android)
        let widthPx = options?["widthPx"] as? Int ?? 384
        let paperWidthMm = options?["paperWidthMm"] as? Int  // Optional paper width
        let keepAlive = options?["keepAlive"] as? Bool ?? false
        let timeoutSec = (options?["timeout"] as? Double ?? 10000) / 1000
        let isCutPaper = options?["isCutPaper"] as? Bool ?? false
        let marginMm = options?["marginMm"] as? Double ?? 0.0
        let alignNum = options?["alignNum"] as? Int ?? 0  // 0=left, 1=center, 2=right

        // Execute print job
        Task {
            let result = await printingModule.printImage(
                address: address,
                imagePath: imagePath,
                widthPx: widthPx,
                paperWidthMm: paperWidthMm,
                keepAlive: keepAlive,
                timeoutSec: timeoutSec,
                isCutPaper: isCutPaper,
                marginMm: marginMm,
                align: alignNum
            )

            DispatchQueue.main.async {
                resolve(result.toDictionary())
            }
        }
    }

    /**
     * Disconnect printer(s)
     * @param address Printer address or null/empty for all
     */
    @objc(disconnect:resolver:rejecter:)
    func disconnect(
        _ address: String?,
        resolve: @escaping RCTPromiseResolveBlock,
        reject: @escaping RCTPromiseRejectBlock
    ) {
        print("[Native:iOS] RNThermalPrinterModule.disconnect - START: \(address ?? "all")")

        printingModule.disconnect(address: address?.isEmpty == true ? nil : address)
        resolve(true)
    }

    /**
     * Cleanup on deinit
     */
    deinit {
        printingModule.cleanup()
    }
}

// MARK: - React Native Module Export

@objc(RNThermalPrinter)
extension RNThermalPrinter {
    override static func moduleName() -> String! {
        return "RNThermalPrinter"
    }
}