////
////  RNOkayCamPlus.swift
////  RNOkayCamPlus
////
////  Created by Mohammad Ashraful Kabir on 03/09/2025.
////  Copyright © 2025 Facebook. All rights reserved.
////

import Foundation
import OkayCamPlus

@objc(RNOkayCamPlus)
class RNOkayCamPlus: NSObject {
    
    var promiseResolve: RCTPromiseResolveBlock?
    var promiseReject: RCTPromiseRejectBlock?
    
    @objc func captureDocument(
        _ configs: NSDictionary,
        resolver resolve: @escaping RCTPromiseResolveBlock,
        rejecter reject: @escaping RCTPromiseRejectBlock
    ) {

        guard let license = configs["license"] as? String else {
            reject("invalid_license", "Missing license", nil)
            return
        }

        let base64 = configs["base64"] as? Bool ?? false
        let rnOkayCamConfig = configs["config"] as? NSDictionary ?? [:]

        let width = rnOkayCamConfig["width"] as? Int
        let imageQuality = rnOkayCamConfig["imageQuality"] as? CGFloat
        let mode = rnOkayCamConfig["mode"] as? String
        let autoCapture = rnOkayCamConfig["autoCapture"] as? Bool

        DispatchQueue.main.async {
            guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, 
                let rootViewController = scene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
                    reject("no_root_view_controller", "Root view controller not found", nil)
                    return
            }

            let config = OkayCamAutoCaptureConfig(viewController: rootViewController)

            // width
            if let width = width, width != -1 {
                config.width = width
            }

            // image quality
            if let imageQuality = imageQuality, imageQuality > 0.0 {
                config.imageQuality = imageQuality
            }

            // ✅ FIX: allow false
            if let autoCapture = autoCapture {
                config.autoCapture = autoCapture
            }

            config.mode = self.parseMode(mode)

            OkayCamAutoDoc.start(
                okayCamConfig: config,
                license: license
            ) { filePaths, error in

                if let error = error {
                    self.handleError(error, rejecter: reject)
                    return
                }

                guard let urls = filePaths else {
                    reject("no_result", "No images returned", nil)
                    return
                }

                do {
                    let result: NSMutableDictionary = [:]

                    result["fullDocumentImage"] = self.convertImgToBase64(base64: base64, image: urls[0])

                    if urls.count > 1 {
                        result["fullDocumentImage2"] = self.convertImgToBase64(base64: base64, image: urls[1])
                    }
                    if urls.count > 2 {
                        result["fullDocumentImage3"] = self.convertImgToBase64(base64: base64, image: urls[2])
                    }
                    if urls.count > 3 {
                        result["fullDocumentImage4"] = self.convertImgToBase64(base64: base64, image: urls[3])
                    }

                    let jsonData = try JSONSerialization.data(withJSONObject: result)
                    let jsonString = String(data: jsonData, encoding: .utf8)!

                    resolve(jsonString)

                } catch {
                    reject("json_error", error.localizedDescription, error)
                }
            }
        }
    }
    
    @objc func captureSelfie(_ configs: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        
        let license = configs.object(forKey: "license")! as! String
        let base64 = configs.object(forKey: "base64") as! Bool
        let rnOkayCamConfig = configs.object(forKey: "config") as! NSDictionary
        let topLabel = rnOkayCamConfig.object(forKey: "topLabel") as! NSDictionary
        let bottomFrameColor = rnOkayCamConfig.object(forKey: "bottomFrameColor") as! String
        let captureBtnColor = rnOkayCamConfig.object(forKey: "captureBtnColor") as! String
        let switchBtnConfig = rnOkayCamConfig.object(forKey: "switchBtnConfig") as! NSDictionary
        let confirmBtnConfig = rnOkayCamConfig.object(forKey: "confirmBtnConfig") as! NSDictionary
        let retakeBtnConfig = rnOkayCamConfig.object(forKey: "retakeBtnConfig") as! NSDictionary
        let defaultCameraFacing = rnOkayCamConfig.object(forKey: "defaultCameraFacing") as! String
        let width = rnOkayCamConfig.object(forKey: "width") as! Int
        let imageQuality = rnOkayCamConfig.object(forKey: "imageQuality") as! CGFloat
        
        DispatchQueue.main.async {
            guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, 
                let rootViewController = scene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
                    reject("no_root_view_controller", "Root view controller not found", nil)
                    return
            }
            
            let okaySelfieConfig = OkaySelfieConfig(viewController: rootViewController)
            
            // top label
            okaySelfieConfig.topLabel.text = topLabel.object(forKey: "text") as! String
            okaySelfieConfig.topLabel.color = self.hexStringToUIColor(hex: topLabel.object(forKey: "color") as! String)
            okaySelfieConfig.topLabel.size = CGFloat(topLabel.object(forKey: "size") as! Int)
            
            // bottom frame color
            okaySelfieConfig.bottomFrameColor = self.hexStringToUIColor(hex: bottomFrameColor)
            
            // capture button color
            okaySelfieConfig.captureBtnColor = self.hexStringToUIColor(hex: captureBtnColor)
            
            // capture configurations
            okaySelfieConfig.captureBtnColor = self.hexStringToUIColor(hex: captureBtnColor)

            // confirm button config
            okaySelfieConfig.confirmBtnConfig.backgroundColor = self.hexStringToUIColor(hex: confirmBtnConfig.object(forKey: "backgroundColor") as! String)
            okaySelfieConfig.confirmBtnConfig.contentColor = self.hexStringToUIColor(hex: confirmBtnConfig.object(forKey: "contentColor") as! String)

            // retake button config
            okaySelfieConfig.retakeBtnConfig.backgroundColor = self.hexStringToUIColor(hex: retakeBtnConfig.object(forKey: "backgroundColor") as! String)
            okaySelfieConfig.retakeBtnConfig.contentColor = self.hexStringToUIColor(hex: retakeBtnConfig.object(forKey: "contentColor") as! String)
            
            // switch button config
            okaySelfieConfig.switchBtnConfig.color = self.hexStringToUIColor(hex: switchBtnConfig.object(forKey: "color") as! String)
//            okaySelfieConfig.switchBtnConfig.show = switchBtnConfig.object(forKey: "show") as! Bool
            okaySelfieConfig.switchBtnConfig.show = true
            // camera facing
            if (defaultCameraFacing == "front") {
                okaySelfieConfig.defaultCameraFacing = OkayCamPlus.CameraDevice.front
            }
            else {
                okaySelfieConfig.defaultCameraFacing = OkayCamPlus.CameraDevice.back
            }
            
            // resize
            if (width != -1) {
                okaySelfieConfig.width = width
            }
            
            okaySelfieConfig.imageQuality = imageQuality

            let shortLicense = license.components(separatedBy: ":")[0]
            print("License key: \(shortLicense)")

            // start the SDK
            OkayCamSelfie.start(
                okaySelfieConfig: okaySelfieConfig,
                license: shortLicense,
                { filePath, error in
                    // handle error
                    do {
                        if let failed = error {
                            print(failed)
                            self.handleError(failed, rejecter: reject)
                        }
                        
                        // handle success
                        if let url = filePath {
                            let selfieValue = base64 ? self.convertImgToBase64(base64: true, image: url) : url.absoluteString

                            let okayCamObject: [String: Any] = ["selfieImage": selfieValue]

                            if let jsonData = try? JSONSerialization.data(withJSONObject: okayCamObject, options: .prettyPrinted),
                            let jsonString = String(data: jsonData, encoding: .ascii) {
                                resolve(jsonString)
                            } else {
                                reject("JSON_ERROR", "Failed to serialize selfie data", nil)
                            }
                        }
                    } catch {
                        print("Error:", error)
                        reject("E_INVALID_RESULT", "Invalid or missing result", nil)
                    }
                }
            )
        }
    }

    @objc func captureSelfiePlus(_ configs: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {

        let license = configs.object(forKey: "license")! as! String
        let base64 = configs.object(forKey: "base64") as! Bool

        print("License key: \(license)")
        print("base64: \(base64)")

        DispatchQueue.main.async {
            guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, 
                let rootViewController = scene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
                    reject("no_root_view_controller", "Root view controller not found", nil)
                    return
            }
            
            // start the SDK
            OkayCamPlusSelfie.start(
                viewController: rootViewController,
                license: license,
                { result, error in
                    if let failed = error {
                        print("❌ SDK Error:", failed)
                        self.handleError(failed, rejecter: reject)
                        return
                    }
                    
                    if let jsonString = result {
                        if var jsonObject = try? JSONSerialization.jsonObject(with: Data(jsonString.utf8), options: []) as? [String: Any] {
                            if let selfiePath = jsonObject["selfie"] as? String {
                                jsonObject["selfie"] = base64 ? self.convertImgToBase64(base64: true, image: URL(string: selfiePath)!) : selfiePath
                            }

                            if let updatedData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
                            let updatedString = String(data: updatedData, encoding: .ascii) {
                                resolve(updatedString)
                            } else {
                                reject("JSON_ERROR", "Failed to serialize updated JSON", nil)
                            }
                        } else {
                            reject("E_INVALID_RESULT", "Invalid JSON format", nil)
                        }
                    } else {
                        reject("E_INVALID_RESULT", "Nil result", nil)
                    }
                }
            )
        }
    }
    
    func convertImgToBase64 (base64: Bool, image:URL) -> String {
        var result = image.absoluteString
        
        if (base64) {
            do {
                result = try convertImageToBase64(fileUrl: image)
            }
            catch {
                print("Error:", error)
            }
        }
        
        return result
    }
    
    func hexStringToUIColor (hex:String,alpha : Float = 1.0) -> UIColor {
        var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        
        if (cString.hasPrefix("#")) {
            cString.remove(at: cString.startIndex)
        }
        
        if ((cString.count) != 6) {
            return UIColor.gray
        }
        
        var rgbValue:UInt64 = 0
        Scanner(string: cString).scanHexInt64(&rgbValue)
        
        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(alpha)
        )
    }
    
    func handleError(
        _ error: OkayCamError,
        rejecter reject: @escaping RCTPromiseRejectBlock
    ) {
        switch error {

        case .camera(let errorMsg):
            reject(
                "CAMERA_ERROR",
                errorMsg,
                nil
            )

        case .invalidConfig(let errorMsg):
            reject(
                "INVALID_CONFIG",
                errorMsg,
                nil
            )

        case .imageCapture(let errorMsg):
            reject(
                "IMAGE_CAPTURE_ERROR",
                errorMsg,
                nil
            )

        case .userCancelled:
            reject(
                "USER_CANCELLED",
                "User cancelled",
                nil
            )

        case .miscellaneous(let errorMsg):
            reject(
                "MISCELLANEOUS_ERROR",
                errorMsg,
                nil
            )

        case .invalidLicense:
            reject(
                "INVALID_LICENSE",
                "Invalid license",
                nil
            )

        case .noError:
            reject(
                "UNKNOWN_ERROR",
                "Unknown error",
                nil
            )

        case .cameraPermission:
            reject(
                "CAMERA_PERMISSION_DENIED",
                "Camera permission denied",
                nil
            )

        case .failedToCreateIADBundle:
            reject(
                "FAILED_TO_CREATE_IAD_BUNDLE",
                "Failed to create IAD bundle",
                nil
            )

        @unknown default:
            reject(
                "UNKNOWN_ERROR",
                "Unknown error",
                nil
            )
        }
    }

    func parseMode(_ mode: String?) -> OkayCamAutoCaptureMode {
        guard let mode = mode else {
            return .full
        }

        switch mode {
        case "FRONT_ONLY":
            return .frontOnly
            
        case "FRONT_BACK":
            return .frontBack
            
        case "FRONT_WITH_FLASH":
            return .frontWithFlash
            
        default:
            return .full
        }
    }
}
