import SwiftUI

#if !TESTING
import CheckoutComponentsSDK
#endif

@objc(Appearance)
public class Appearance: NSObject {
  
  // MARK: - Public Methods
  
  public func buildDesignTokens(from styleDict: [String: Any]) -> CheckoutComponents.DesignTokens {
    let colorTokens = extractColorTokens(from: styleDict["colorTokens"] as? [String: Any])
    
    let fonts = extractFonts(from: styleDict["fonts"] as? [String: Any])
    
    let borderButtonRadius = extractBorderRadius(from: styleDict["borderButtonRadius"])
    let borderFormRadius = extractBorderRadius(from: styleDict["borderFormRadius"])
    
    let tokens = CheckoutComponents.DesignTokens(
      colorTokensMain: colorTokens,
      fonts: fonts,
      borderButtonRadius: borderButtonRadius,
      borderFormRadius: borderFormRadius
    )
    
    return tokens
  }
  
  public func processStyleConfiguration(from style: [String: Any]) -> CheckoutComponents.DesignTokens? {
    let tokens = buildDesignTokens(from: style)
    return tokens
  }
  
  // MARK: - Private Extraction Methods
  
  private func extractColorTokens(from colorTokensDict: [String: Any]?) -> CheckoutComponents.ColorTokens {
    guard let colorTokensDict = colorTokensDict else {
      return CheckoutComponents.ColorTokens()
    }
    
    return CheckoutComponents.ColorTokens(
      action: colorFromString(colorTokensDict["action"] as? String) ?? Color.brightBlue,
      background: colorFromString(colorTokensDict["background"] as? String) ?? Color.white,
      border: colorFromString(colorTokensDict["border"] as? String) ?? Color.softGray,
      disabled: colorFromString(colorTokensDict["disabled"] as? String) ?? Color.brightGray,
      error: colorFromString(colorTokensDict["error"] as? String) ?? Color.deepRed,
      formBackground: colorFromString(colorTokensDict["formBackground"] as? String) ?? Color.white,
      formBorder: colorFromString(colorTokensDict["formBorder"] as? String) ?? Color.mediumGray,
      inverse: colorFromString(colorTokensDict["inverse"] as? String) ?? Color.white,
      outline: colorFromString(colorTokensDict["outline"] as? String) ?? Color.lightBlue,
      primary: colorFromString(colorTokensDict["primary"] as? String) ?? Color.black,
      secondary: colorFromString(colorTokensDict["secondary"] as? String) ?? Color.lightGray,
      success: colorFromString(colorTokensDict["success"] as? String) ?? Color.checkoutGreen
    )
  }
  
  private func extractFonts(from fontsDict: [String: Any]?) -> CheckoutComponents.Font.Style {
    guard let fontsDict = fontsDict else {
      return CheckoutComponents.Font.Style()
    }
    
    let buttonFont = extractFont(from: fontsDict["button"] as? [String: Any], defaultFont: .button)
    let footnoteFont = extractFont(from: fontsDict["footnote"] as? [String: Any], defaultFont: .footnote)
    let inputFont = extractFont(from: fontsDict["input"] as? [String: Any], defaultFont: .input)
    let labelFont = extractFont(from: fontsDict["label"] as? [String: Any], defaultFont: .label)
    let subheadingFont = extractFont(from: fontsDict["subheading"] as? [String: Any], defaultFont: .subheading)
    
    return CheckoutComponents.Font.Style(
      button: buttonFont,
      footnote: footnoteFont,
      input: inputFont,
      label: labelFont,
      subheading: subheadingFont
    )
  }
  
  private func mapFontWeight(_ number: Double?) -> Font.Weight {
    guard let number = number else { return .regular }
    
    switch number {
    case ..<150: return .ultraLight
    case ..<250: return .thin
    case ..<350: return .light
    case ..<450: return .regular
    case ..<550: return .medium
    case ..<650: return .semibold
    case ..<750: return .bold
    case ..<850: return .heavy
    default: return .black
    }
  }
  
  private func buildFont(
    fontFamily: String?,
    fontSize: CGFloat,
    fontWeight: Font.Weight,
    lineHeight: CGFloat,
    letterSpacing: CGFloat
  ) -> (font: Font, lineHeight: CGFloat, letterSpacing: CGFloat) {
    let font: Font
    if let family = fontFamily, !family.isEmpty {
      font = Font.custom(family, size: fontSize).weight(fontWeight)
    } else {
      font = Font.system(size: fontSize, weight: fontWeight)
    }
    
    return (font: font, lineHeight: lineHeight, letterSpacing: letterSpacing)
  }
  
  private func extractFont(
    from fontDict: [String: Any]?,
    defaultFont: CheckoutComponents.Font
  ) -> CheckoutComponents.Font {
    guard let fontDict = fontDict else {
      return defaultFont
    }
    
    let family = fontDict["fontFamily"] as? String
    let size = CGFloat((fontDict["fontSize"] as? Double) ?? 17.0)
    let weightValue = fontDict["fontWeight"] as? Double
    let lineHeight = CGFloat((fontDict["lineHeight"] as? Double) ?? 8)
    let letterSpacing = CGFloat((fontDict["letterSpacing"] as? Double) ?? 0.0)
    
    let weight = mapFontWeight(weightValue)
    
    let result = buildFont(
      fontFamily: family,
      fontSize: size,
      fontWeight: weight,
      lineHeight: lineHeight,
      letterSpacing: letterSpacing
    )
    
    return CheckoutComponents.Font(
      font: result.font,
      lineHeight: result.lineHeight,
      letterSpacing: result.letterSpacing
    )
  }
  
  private func extractBorderRadius(from value: Any?) -> CheckoutComponents.BorderRadius {
    if let number = value as? NSNumber {
      return CheckoutComponents.BorderRadius(radius: number.doubleValue)
    }
    return CheckoutComponents.BorderRadius(radius: 8.0)
  }
  
  private func colorFromString(_ colorString: String?) -> Color? {
    guard let colorString = colorString,
          !colorString.isEmpty else {
      return nil
    }
    
    let hex = colorString.hasPrefix("#") ? String(colorString.dropFirst()) : colorString
    
    guard hex.count == 6,
          let hexValue = Int(hex, radix: 16) else {
      return nil
    }
    
    let red = Double((hexValue & 0xFF0000) >> 16) / 255.0
    let green = Double((hexValue & 0x00FF00) >> 8) / 255.0
    let blue = Double(hexValue & 0x0000FF) / 255.0
    
    return Color(red: red, green: green, blue: blue)
  }
}

// MARK: - Color Token Access Extension

extension Appearance {
  @objc public func getAvailableColorTokenKeys() -> [String] {
    return [
      "primary", "background", "action", "border", "disabled", "error",
      "formbackground", "formborder", "inverse", "outline", "secondary", "success"
    ]
  }
}
