import Foundation
import touchlesslib
import AVFoundation
import SwiftUI

public class Utils {

  public static func dictionaryToFingerprintConfig(config: NSDictionary) -> FingerprintConfig {
    let fingerConfig = config as! Dictionary<String, Any>
    
    let licenseKey = fingerConfig["licenseKey"] as! String
    let numberFingersToCapture = fingerConfig["numberFingersToCapture"] as! Int
    let fontFamily = fingerConfig["fontFamily"] as! String
    let overlayColor = fingerConfig["overlayColor"] as! String
    let timeToCapture = fingerConfig["timeToCapture"] as! Int

    var resolutionPreset: FingerprintResolutionPreset = .VERYHIGH
        let resolutionPresetString = fingerConfig["resolutionPreset"] as! String
        if (resolutionPresetString == "LOW") {
            resolutionPreset = .LOW
        } else if (resolutionPresetString == "MEDIUM") {
            resolutionPreset = .MEDIUM
        } else if (resolutionPresetString == "HIGH") {
            resolutionPreset = .HIGH
        } else if (resolutionPresetString == "VERYHIGH") {
            resolutionPreset = .VERYHIGH
        } else if (resolutionPresetString == "ULTRAHIGH") {
            resolutionPreset = .ULTRAHIGH
        } else{
            resolutionPreset = .MAX
        }
    
    var captureType: FingerprintCaptureType = .LEFT_HAND_FINGERS
    let captureTypeString = fingerConfig["captureType"] as! String
    if (captureTypeString == "LEFT_HAND_FINGERS") {
      captureType = .LEFT_HAND_FINGERS
    } else if (captureTypeString == "RIGHT_HAND_FINGERS") {
      captureType = .RIGHT_HAND_FINGERS
    } else {
      captureType = .THUMBS
    }
    
    var outputType: FingerprintOutputType = .CAPTURE_AND_SEGMENTATION
    let outputTypeString = fingerConfig["outputType"] as! String
    if (outputTypeString == "CAPTURE_AND_SEGMENTATION") {
      outputType = .CAPTURE_AND_SEGMENTATION
    } else {
      outputType = .ONLY_CAPTURE
    }

    //MARK: GETS CAPTURE COUNTDOWN PROPERTIES
    let mapCaptureCountdown = fingerConfig["captureCountdown"] as! Dictionary<String, AnyObject>
    let captureCountdownEnabled = mapCaptureCountdown["enabled"] as! Bool
    let captureCountdownBackgroundColor = mapCaptureCountdown["backgroundColor"] as! String
    let captureCountdownProgressColor = mapCaptureCountdown["progressColor"] as! String
    let captureCountdownTextColor = mapCaptureCountdown["textColor"] as! String

    //MARK: GETS BACK BUTTON PROPERTIES
    let mapBackButton = fingerConfig["backButton"] as! Dictionary<String, AnyObject>
    let backButtonEnabled = mapBackButton["enabled"] as! Bool
    let backButtonBackgroundColor = mapBackButton["backgroundColor"] as! String
    let backButtonPadding = mapBackButton["buttonPadding"] as! Int
    let mapBackButtonSize = mapBackButton["buttonSize"] as! Dictionary<String, Double>
    let backButtonSize = CGSize(
      width: mapBackButtonSize["width"]!,
      height: mapBackButtonSize["height"]!
    )
    let mapBackButtonIcon = mapBackButton["iconOptions"] as! Dictionary<String, AnyObject>
    let backButtonIconEnabled = mapBackButtonIcon["enabled"] as! Bool
    let backButtonIconFile = mapBackButtonIcon["iconFile"] as! String
    let backButtonIconColor = mapBackButtonIcon["iconColor"] as! String
    let mapBackButtonIconSize = mapBackButtonIcon["iconSize"] as! Dictionary<String, Double>
    let backButtonIconSize = CGSize(
      width: mapBackButtonIconSize["width"]!,
      height: mapBackButtonIconSize["height"]!
    )
    let mapBackButtonLabel = mapBackButton["labelOptions"] as! Dictionary<String, AnyObject>
    let backButtonLabelEnabled = mapBackButtonLabel["enabled"] as! Bool
    let backButtonLabelContent = mapBackButtonLabel["content"] as! String
    let backButtonLabelTextColor = mapBackButtonLabel["textColor"] as! String
    let backButtonLabelTextSize = mapBackButtonLabel["textSize"] as! Int
    
    //MARK: GETS HELP TEXT PROPERTIES
    let mapHelpText = fingerConfig["helpText"] as! Dictionary<String, AnyObject>
    let helpTextEnabled = mapHelpText["enabled"] as! Bool
    let mapHelpMessages = mapHelpText["messages"] as! Dictionary<String, String>
    let leftHandMessage = mapHelpMessages["leftHandMessage"]!
    let rightHandMessage = mapHelpMessages["rightHandMessage"]!
    let thumbsMessage = mapHelpMessages["thumbsMessage"]!
    let helpTextColor = mapHelpText["textColor"] as! String
    let helpTextSize = mapHelpText["textSize"] as! Int

    //MARK: GETS FINGER ELLIPSE PROPERTIES
    let mapFingerEllipse = fingerConfig["fingerEllipse"] as! Dictionary<String, AnyObject>
    let fingerEllipseEnabled = mapFingerEllipse["enabled"] as! Bool
    let fingerEllipseColor = mapFingerEllipse["ellipseColor"] as! String

    //MARK: GETS DISTANCE INDICATOR PROPERTIES
    let mapDistanceIndicator = fingerConfig["distanceIndicator"] as! Dictionary<String, AnyObject>
    let distanceIndicatorEnabled = mapDistanceIndicator["enabled"] as! Bool
    let distanceIndicatorSelectedBarColor = mapDistanceIndicator["selectedBarColor"] as! String
    let distanceIndicatorUnselectedBarColor = mapDistanceIndicator["unselectedBarColor"] as! String
    let distanceIndicatorArrowColor = mapDistanceIndicator["arrowColor"] as! String
    
    //MARK: GETS TOO CLOSE TEXT PROPERTIES
    let mapTooCloseText = mapDistanceIndicator["tooCloseText"] as! Dictionary<String, AnyObject>
    let tooCloseTextEnabled = mapTooCloseText["enabled"] as! Bool
    let tooCloseTextContent = mapTooCloseText["content"] as! String
    let tooCloseTextColor = mapTooCloseText["textColor"] as! String
    let tooCloseTextSize = mapTooCloseText["textSize"] as! Int
    
    //MARK: GETS TOO FAR TEXT PROPERTIES
    let mapTooFarText = mapDistanceIndicator["tooFarText"] as! Dictionary<String, AnyObject>
    let tooFarTextEnabled = mapTooFarText["enabled"] as! Bool
    let tooFarTextContent = mapTooFarText["content"] as! String
    let tooFarTextColor = mapTooFarText["textColor"] as! String
    let tooFarTextSize = mapTooFarText["textSize"] as! Int
    
    let config = FingerprintConfig()
    config.licenseKey = licenseKey
    config.numberFingersToCapture = numberFingersToCapture
    config.fontFamily = fontFamily
    config.overlayColor = Color.convertHexStringToColor(hexString: overlayColor) ?? config.overlayColor
    config.timeToCapture = timeToCapture
    config.resolutionPreset = resolutionPreset
    config.captureType = captureType
    config.outputType = outputType

    //MARK: SETS CAPTURE COUNTDOWN PROPERTIES
    config.captureCountdown.enabled = captureCountdownEnabled
    config.captureCountdown.backgroundColor = Color.convertHexStringToColor(hexString: captureCountdownBackgroundColor) ?? config.captureCountdown.backgroundColor
    config.captureCountdown.progressColor = Color.convertHexStringToColor(hexString: captureCountdownProgressColor) ?? config.captureCountdown.progressColor
    config.captureCountdown.textColor = Color.convertHexStringToColor(hexString: captureCountdownTextColor) ?? config.captureCountdown.textColor

    //MARK: SETS BACK BUTTON PROPERTIES
    config.backButton.enabled = backButtonEnabled
    config.backButton.backgroundColor = Color.convertHexStringToColor(hexString: backButtonBackgroundColor) ?? config.backButton.backgroundColor
    config.backButton.buttonPadding = backButtonPadding
    config.backButton.buttonSize = backButtonSize
    config.backButton.iconOptions.enabled = backButtonIconEnabled
    config.backButton.iconOptions.iconFile = backButtonIconFile
    config.backButton.iconOptions.iconColor = Color.convertHexStringToColor(hexString: backButtonIconColor) ??  config.backButton.iconOptions.iconColor
    config.backButton.iconOptions.iconSize = backButtonIconSize
    config.backButton.labelOptions.enabled = backButtonLabelEnabled
    config.backButton.labelOptions.content = backButtonLabelContent
    config.backButton.labelOptions.textColor = Color.convertHexStringToColor(hexString: backButtonLabelTextColor) ?? config.backButton.labelOptions.textColor
    config.backButton.labelOptions.textSize = CGFloat(backButtonLabelTextSize)
    
    //MARK: SETS HELP TEXT PROPERTIES
    config.helpText.enabled = helpTextEnabled
    config.helpText.messages.leftHandMessage = leftHandMessage
    config.helpText.messages.rightHandMessage = rightHandMessage
    config.helpText.messages.thumbsMessage = thumbsMessage
    config.helpText.textColor = Color.convertHexStringToColor(hexString: helpTextColor) ?? config.helpText.textColor
    config.helpText.textSize = CGFloat(helpTextSize)

    //MARK: SETS FINGER ELLIPSE PROPERTIES
    config.fingerEllipse.enabled = fingerEllipseEnabled
    config.fingerEllipse.ellipseColor = Color.convertHexStringToColor(hexString: fingerEllipseColor) ?? config.fingerEllipse.ellipseColor

    //MARK: SETS DISTANCE INDICATOR PROPERTIES
    config.distanceIndicator.enabled = distanceIndicatorEnabled
    config.distanceIndicator.selectedBarColor = Color.convertHexStringToColor(hexString: distanceIndicatorSelectedBarColor) ?? config.distanceIndicator.selectedBarColor
    config.distanceIndicator.unselectedBarColor = Color.convertHexStringToColor(hexString: distanceIndicatorUnselectedBarColor) ?? config.distanceIndicator.unselectedBarColor
    config.distanceIndicator.arrowColor = Color.convertHexStringToColor(hexString: distanceIndicatorArrowColor) ?? config.distanceIndicator.arrowColor

    //MARK: SETS TOO CLOSE TEXT PROPERTIES
    config.distanceIndicator.tooCloseText.enabled = tooCloseTextEnabled
    config.distanceIndicator.tooCloseText.content = tooCloseTextContent
    config.distanceIndicator.tooCloseText.textColor = Color.convertHexStringToColor(hexString: tooCloseTextColor) ?? config.distanceIndicator.tooCloseText.textColor
    config.distanceIndicator.tooCloseText.textSize = CGFloat(tooCloseTextSize)
    
    //MARK: SETS TOO FAR TEXT PROPERTIES
    config.distanceIndicator.tooFarText.enabled = tooFarTextEnabled
    config.distanceIndicator.tooFarText.content = tooFarTextContent
    config.distanceIndicator.tooFarText.textColor = Color.convertHexStringToColor(hexString: tooFarTextColor) ?? config.distanceIndicator.tooFarText.textColor
    config.distanceIndicator.tooFarText.textSize = CGFloat(tooFarTextSize)
    
    return config
  }
  
  public static func onFingerCaptureEventToNativeMap(images: [UIImage], error: String?) -> Dictionary<String, Any?> {
    var imagesBase64: [String] = []
    for image in images {
      if let imageData = image.pngData() {
        let base64String = imageData.base64EncodedString()
        imagesBase64.append(base64String)
      }
    }
    return ["images": imagesBase64, "error": error]
  }

  public static func onStatusChangedEventToNativeMap(status: FingerprintCaptureState) -> Dictionary<String, String> {
    var stringStatus: String
    if (status == .NO_DETECTION) {
      stringStatus = "noDetection"
    } else if(status == .MISSING_FINGERS) {
      stringStatus = "missingFingers"
    } else if(status == .TOO_CLOSE) {
      stringStatus = "tooClose"
    } else if(status == .TOO_FAR) {
      stringStatus = "tooFar"
    } else if(status == .OK) {
      stringStatus = "ok"
    } else if(status == .STOPPED) {
      stringStatus = "stopped"
    } else if(status == .PROCESSING) {
      stringStatus = "processing"
    } else {
      stringStatus = "modelNotFound"
    }
    let result = ["state": stringStatus]
    return result
  }
  
  public static func onFingerDetectedEventToNativeMap(fingerRects: [CGRect]) -> Dictionary<String, Any> {
    var rectList: [Dictionary<String, Any>] = []
    for rect in (fingerRects as NSArray as! [CGRect]) {
      let dataRect = [
        "left": rect.origin.x,
        "top": rect.origin.y,
        "right": rect.origin.x + rect.size.width,
        "bottom": rect.origin.y + rect.size.height,
      ]
      rectList.append(dataRect)
    }
    let result = ["fingerRects": rectList]
    return result
  }

}

extension Color {

  static func convertHexStringToColor(hexString: String) -> Color? {
    var cString: String = hexString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
    
    if (cString.hasPrefix("#")) {
      cString.remove(at: cString.startIndex)
    }
    
    if ((cString.count) != 8 && (cString.count) != 6) {
      return nil
    }
    
    var rgbValue: UInt64 = 0
    Scanner(string: cString).scanHexInt64(&rgbValue)
    
    if ((cString.count) == 8) {
      return Color(.sRGB, red: Double((rgbValue & 0x00FF0000) >> 16) / 255.0, green: Double((rgbValue & 0x0000FF00) >> 8) / 255.0, blue: Double(rgbValue & 0x000000FF) / 255.0, opacity: Double(Int(rgbValue & 0xFF000000) >> 24) / 255.0)
    } else {
      return Color(.sRGB, red: Double((rgbValue & 0xFF0000) >> 16) / 255.0, green: Double((rgbValue & 0x00FF00) >> 8) / 255.0, blue: Double(rgbValue & 0x0000FF) / 255.0)
    }
  }
  
  static func convertHexStringToUIColor(hexString: String) -> UIColor? {
    var formattedString = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
    formattedString = formattedString.replacingOccurrences(of: "#", with: "")
    
    let hexCount = formattedString.count
    if hexCount != 6 && hexCount != 8 {
      return nil
    }
    
    var rgbValue: UInt64 = 0
    Scanner(string: formattedString).scanHexInt64(&rgbValue)

    let red = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0
    let green = CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0
    let blue = CGFloat(rgbValue & 0x0000FF) / 255.0

    return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
  }

}
