//
//  LunarDatePicker.swift
//  LunarDatePicker
//
//  Main entry point for React Native Nitro Module
//

import Foundation
import UIKit

/// Main class implementing the HybridLunarDatePickerSpec protocol
/// This class serves as the bridge between React Native and native iOS implementation
final class LunarDatePicker: HybridLunarDatePickerSpec {

  // MARK: - Properties

  /// Coordinator responsible for managing the presentation flow
  private let coordinator: LunarDatePickerCoordinator

  // MARK: - Initialization

  /// Initializes the LunarDatePicker with default dependencies
  override init() {
    self.coordinator = LunarDatePickerCoordinator()
  }

  /// Initializes the LunarDatePicker with custom dependencies (for testing)
  /// - Parameter coordinator: Custom coordinator instance
  init(coordinator: LunarDatePickerCoordinator) {
    self.coordinator = coordinator
  }

  // MARK: - HybridLunarDatePickerSpec Implementation

  /// Configures the global settings for the date picker
  /// - Parameter config: Configuration parameters including themes, languages, etc.
  /// - Throws: An error if configuration is invalid
  public func configure(config: LDP_ConfigParams) throws {
    // Validate configuration before applying
    try validateConfiguration(config)

    // Apply configuration to coordinator
    coordinator.configure(with: config)
  }

  /// Presents the date picker with the specified parameters
  /// - Parameter params: Presentation parameters including mode, theme, language, etc.
  /// - Throws: An error if presentation fails
  public func present(params: LDP_PresentParams) throws {
    // Ensure we're on the main thread for UI operations
    guard Thread.isMainThread else {
      DispatchQueue.main.async { [weak self] in
        try? self?.present(params: params)
      }
      return
    }

    // Validate presentation parameters
    try validatePresentationParams(params)

    // Present using coordinator
    try coordinator.present(with: params)
  }

  /// Updates prices for the currently displayed calendar
  /// - Parameter params: Price update parameters with mode and data
  /// - Throws: An error if update fails
  public func updatePrices(params: LDP_PriceUpdateParams) throws {
    // Ensure we're on the main thread for UI operations
    guard Thread.isMainThread else {
      DispatchQueue.main.async { [weak self] in
        try? self?.updatePrices(params: params)
      }
      return
    }

    // Update using coordinator
    try coordinator.updatePrices(params)
  }

  // MARK: - Private Methods

  /// Validates the configuration parameters
  /// - Parameter config: Configuration to validate
  /// - Throws: LunarDatePickerError.invalidConfiguration if validation fails
  private func validateConfiguration(_ config: LDP_ConfigParams) throws {
    // Validate themes
    for (_, theme) in config.themes {
      guard isValidHexColor(theme.backgroundColor),
        isValidHexColor(theme.titleColor),
        isValidHexColor(theme.cancelColor),
        isValidHexColor(theme.dateLabelColor),
        isValidHexColor(theme.lunarDateLabelColor),
        isValidHexColor(theme.selectedTextColor),
        isValidHexColor(theme.weekendLabelColor),
        isValidHexColor(theme.specialDayLabelColor),
        isValidHexColor(theme.monthLabelColor),
        isValidHexColor(theme.weekViewBackgroundColor),
        isValidHexColor(theme.selectedBackgroundColor),
        isValidHexColor(theme.rangeBackgroundColor),
        isValidHexColor(theme.priceLabelColor),
        isValidHexColor(theme.cheapestPriceLabelColor)
      else {
        throw LunarDatePickerError.invalidConfiguration
      }
    }

    // Validate languages
    for (_, language) in config.languages {
      guard language.weekdayNames.count == 7,
        language.monthNames.count == 12
      else {
        throw LunarDatePickerError.invalidConfiguration
      }
    }
  }

  /// Validates the presentation parameters
  /// - Parameter params: Presentation parameters to validate
  /// - Throws: LunarDatePickerError.invalidConfiguration if validation fails
  private func validatePresentationParams(_ params: LDP_PresentParams) throws {
    // Validate date ranges if provided
    if let minimumDate = params.minimumDate,
      let maximumDate = params.maximumDate
    {
      guard minimumDate < maximumDate else {
        throw LunarDatePickerError.invalidConfiguration
      }
    }

    // Validate initial value if provided
    if let initialValue = params.initialValue {
      if let toDate = initialValue.to {
        let fromDate = initialValue.from
        guard fromDate <= toDate else {
          throw LunarDatePickerError.invalidConfiguration
        }
      }
    }
  }

  /// Checks if a string is a valid hex color
  /// - Parameter hex: Hex color string to validate
  /// - Returns: true if valid hex color, false otherwise
  private func isValidHexColor(_ hex: String) -> Bool {
    let hexRegex = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$"
    let hexPredicate = NSPredicate(format: "SELF MATCHES %@", hexRegex)
    return hexPredicate.evaluate(with: hex)
  }
}
