//
//  DayCell.swift
//  Pods
//
//  Created by Nguyen Van Duong on 7/4/25.
//

import Foundation
import JTAppleCalendar
import UIKit

final class DayCell: JTACDayCell {

  // MARK: - UI Components

  lazy var dateContainerView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
  }()

  lazy var priceContainerView: UIView = {
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.isHidden = true
    return view
  }()

  lazy var dateLabel: UILabel = {
    let label = UILabel()
    label.textAlignment = .center
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(
      ofSize: Constants.FontSize.dateLabel,
      weight: .regular
    )
    return label
  }()

  lazy var lunarDateLabel: UILabel = {
    let label = UILabel()
    label.textAlignment = .center
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(
      ofSize: Constants.FontSize.lunarDateLabel,
      weight: .regular
    )
    return label
  }()

  lazy var priceLabel: UILabel = {
    let label = UILabel()
    label.textAlignment = .center
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: Constants.FontSize.priceLabel)
    label.alpha = 1.0
    return label
  }()

  lazy var selectionBackgroundView: UIView = {
    let view = UIView()
    view.isHidden = true
    view.translatesAutoresizingMaskIntoConstraints = false
    view.layer.masksToBounds = true
    return view
  }()

  lazy var leftRangeView: UIView = {
    let view = UIView()
    view.layer.masksToBounds = true
    view.layer.cornerCurve = .continuous
    view.layer.cornerRadius = Constants.UI.rangeViewCornerRadius
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
  }()

  lazy var rightRangeView: UIView = {
    let view = UIView()
    view.layer.masksToBounds = true
    view.layer.cornerCurve = .continuous
    view.layer.cornerRadius = Constants.UI.rangeViewCornerRadius
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
  }()

  // MARK: - Properties

  private var config: PickerConfig = PickerConfig.default
  private var isPriceContainerConfigured: Bool = false
  private var priceContainerConstraints: [NSLayoutConstraint] = []

  // MARK: - Lifecycle

  override init(frame: CGRect) {
    super.init(frame: frame)
    setupViews()
    setupConstraints()
    applyConfig(.default)
  }

  @available(*, unavailable)
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func layoutSubviews() {
    super.layoutSubviews()
    updateSelectionBackgroundCornerRadius()
  }

  override func prepareForReuse() {
    super.prepareForReuse()
    resetCell()
  }

  // MARK: - Public Methods

  public func applyConfig(_ config: PickerConfig) {
    self.config = config
    updateViewsWithConfig()
  }

  public func configure(for config: ViewConfig) {
    configureVisibility(config)
    configureContent(config)
    configureRangeViews(config)
    
    // Ensure corner radius is updated for visible selection
    if !config.isSelectedViewHidden {
      DispatchQueue.main.async {
        self.updateSelectionBackgroundCornerRadius()
      }
    }
  }

  // MARK: - Private Methods

  private func setupViews() {
    // Add base views
    contentView.addSubview(leftRangeView)
    contentView.addSubview(rightRangeView)
    contentView.addSubview(dateContainerView)
    
    // Add date container content
    dateContainerView.addSubview(selectionBackgroundView)
    dateContainerView.addSubview(dateLabel)
    dateContainerView.addSubview(lunarDateLabel)
    
    // Price container will be added when needed
  }

  private func setupConstraints() {
    setupDateContainerConstraints()
    setupRangeViewConstraints()
    setupSelectionBackgroundConstraints()
  }

  private func setupDateContainerConstraints() {
    NSLayoutConstraint.activate([
      dateContainerView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
      dateContainerView.topAnchor.constraint(equalTo: contentView.topAnchor),
      dateContainerView.widthAnchor.constraint(equalTo: contentView.widthAnchor),
      
      dateLabel.centerXAnchor.constraint(equalTo: dateContainerView.centerXAnchor),
      dateLabel.topAnchor.constraint(equalTo: dateContainerView.topAnchor),
      
      lunarDateLabel.centerXAnchor.constraint(equalTo: dateContainerView.centerXAnchor),
      lunarDateLabel.topAnchor.constraint(
        equalTo: dateLabel.bottomAnchor,
        constant: Constants.Layout.lunarDateLabelTopSpacing
      ),
      lunarDateLabel.bottomAnchor.constraint(equalTo: dateContainerView.bottomAnchor)
    ])
  }

  private func setupRangeViewConstraints() {
    NSLayoutConstraint.activate([
      leftRangeView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
      leftRangeView.rightAnchor.constraint(equalTo: contentView.centerXAnchor),
      leftRangeView.topAnchor.constraint(equalTo: dateContainerView.topAnchor, constant: -1),
      leftRangeView.bottomAnchor.constraint(equalTo: dateContainerView.bottomAnchor, constant: 2),
      
      rightRangeView.leftAnchor.constraint(equalTo: contentView.centerXAnchor),
      rightRangeView.rightAnchor.constraint(
        equalTo: contentView.rightAnchor,
        constant: Constants.Layout.cellPadding
      ),
      rightRangeView.topAnchor.constraint(equalTo: dateContainerView.topAnchor, constant: -1),
      rightRangeView.bottomAnchor.constraint(equalTo: dateContainerView.bottomAnchor, constant: 2)
    ])
  }

  private func setupSelectionBackgroundConstraints() {
    NSLayoutConstraint.activate([
      selectionBackgroundView.centerXAnchor.constraint(equalTo: dateContainerView.centerXAnchor),
      selectionBackgroundView.centerYAnchor.constraint(equalTo: dateContainerView.centerYAnchor),
      selectionBackgroundView.widthAnchor.constraint(
        equalTo: dateContainerView.heightAnchor,
        constant: 6
      ),
      selectionBackgroundView.heightAnchor.constraint(
        equalTo: dateContainerView.heightAnchor,
        constant: 6
      )
    ])
  }

  private func setupPriceContainerIfNeeded() {
    guard !isPriceContainerConfigured else { return }
    
    contentView.addSubview(priceContainerView)
    priceContainerView.addSubview(priceLabel)
    
    priceContainerConstraints = [
      priceContainerView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
      priceContainerView.topAnchor.constraint(
        equalTo: dateContainerView.bottomAnchor,
        constant: Constants.Layout.priceLabelTopSpacing
      ),
      priceContainerView.widthAnchor.constraint(equalTo: contentView.widthAnchor),
      
      priceLabel.centerXAnchor.constraint(equalTo: priceContainerView.centerXAnchor),
      priceLabel.topAnchor.constraint(equalTo: priceContainerView.topAnchor),
      priceLabel.bottomAnchor.constraint(equalTo: priceContainerView.bottomAnchor)
    ]
    
    NSLayoutConstraint.activate(priceContainerConstraints)
    isPriceContainerConfigured = true
  }

  private func updateViewsWithConfig() {
    let backgroundColor = config.dayCell.rangeBackgroundColor.toUIColor()
    
    leftRangeView.backgroundColor = backgroundColor
    rightRangeView.backgroundColor = backgroundColor
    
    selectionBackgroundView.backgroundColor = config.dayCell.selectedBackgroundColor.toUIColor()
    dateLabel.textColor = config.dayCell.dateLabelColor.toUIColor()
    lunarDateLabel.textColor = config.dayCell.lunarDateLabelColor.toUIColor()
  }

  private func updateSelectionBackgroundCornerRadius() {
    // Use actual frame if available, otherwise estimate based on constraints
    let frame = selectionBackgroundView.frame
    let radius: CGFloat
    
    if frame.width > 0 && frame.height > 0 {
      // Use actual frame
      radius = max(frame.width, frame.height) / 2
    } else {
      // Estimate radius based on dateContainerView or fallback to a reasonable default
      let containerFrame = dateContainerView.frame
      if containerFrame.height > 0 {
        // Based on constraint: heightAnchor = dateContainerView.heightAnchor + 8
        radius = (containerFrame.height + 8) / 2
      } else {
        // Fallback radius for different cell sizes
        radius = 20 // Reasonable default for circular selection
      }
    }
    
    selectionBackgroundView.layer.cornerRadius = radius
  }

  private func resetCell() {
    dateLabel.isHidden = false
    lunarDateLabel.isHidden = false
    priceContainerView.isHidden = true
    
    selectionBackgroundView.isHidden = true
    leftRangeView.isHidden = true
    rightRangeView.isHidden = true
    
    isUserInteractionEnabled = true
    clipsToBounds = false
    
    // Reset alpha values
    dateLabel.alpha = 1.0
    lunarDateLabel.alpha = 1.0
    priceLabel.alpha = 1.0
  }

  private func configureVisibility(_ config: ViewConfig) {
    let hasDateContent = config.dateLabelText != nil
    let hasPriceContent = config.priceLabelText != nil
    
    dateLabel.isHidden = !hasDateContent
    lunarDateLabel.isHidden = !hasDateContent
    
    let wasHidden = selectionBackgroundView.isHidden
    selectionBackgroundView.isHidden = config.isSelectedViewHidden
    
    // Force update corner radius when selection becomes visible
    if wasHidden && !config.isSelectedViewHidden {
      setNeedsLayout()
      layoutIfNeeded()
      updateSelectionBackgroundCornerRadius()
      
      // Additional update on next run loop to ensure frame is ready
      DispatchQueue.main.async {
        self.updateSelectionBackgroundCornerRadius()
      }
    }
    
    isUserInteractionEnabled = hasDateContent && config.isDateEnabled && config.lunarDateLabelText != nil
    clipsToBounds = !hasDateContent || config.lunarDateLabelText == nil
    
    // Handle price container
    if hasPriceContent {
      setupPriceContainerIfNeeded()
      priceContainerView.isHidden = false
    } else if isPriceContainerConfigured {
      priceContainerView.isHidden = true
    }
  }

  private func configureContent(_ config: ViewConfig) {
    // Configure date labels
    if let dateLabelText = config.dateLabelText {
      dateLabel.text = dateLabelText
      dateLabel.textColor = config.dateLabelColor.toUIColor()
      dateLabel.font = UIFont.systemFont(ofSize: Constants.FontSize.dateLabel, weight: config.dateLabelFontWeight)
      
      lunarDateLabel.text = config.lunarDateLabelText
      lunarDateLabel.textColor = config.lunarDateLabelColor.toUIColor()
      
      // Configure enabled/disabled state
      let alpha: CGFloat = config.isDateEnabled ? 1.0 : 0.4
      dateLabel.alpha = alpha
      lunarDateLabel.alpha = alpha
      
      // Override colors for selected state
      if !config.isSelectedViewHidden {
        let selectedColor = self.config.dayCell.selectedTextColor.toUIColor()
        dateLabel.textColor = selectedColor
        lunarDateLabel.textColor = selectedColor
      }
    }
    
    // Configure price label
    if let priceLabelText = config.priceLabelText {
      priceLabel.text = priceLabelText
      priceLabel.textColor = config.priceLabelColor.toUIColor()
      priceLabel.alpha = config.isDateEnabled ? 1.0 : 0.4
    }
  }

  private func configureRangeViews(_ config: ViewConfig) {
    configureRangeView(rightRangeView, for: config.rangeView.rightSideState)
    configureRangeView(leftRangeView, for: config.rangeView.leftSideState)
  }

  private func configureRangeView(_ view: UIView, for state: RangeSideState) {
    switch state {
    case .squared:
      view.isHidden = false
      view.layer.maskedCorners = []
    case .rounded:
      view.isHidden = false
      view.layer.maskedCorners = view == rightRangeView
        ? [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
        : [.layerMinXMinYCorner, .layerMinXMaxYCorner]
    case .hidden:
      view.isHidden = true
    }
  }
}

// MARK: - Static Factory Methods

extension DayCell {
  public static func makeViewConfig(
    for state: CellState,
    minimumDate: Date?,
    maximumDate: Date?,
    rangeValue: PickerRange?,
    calendar: Calendar,
    dateLabelColor: ColorWrapper = ColorWrapper.label,
    lunarDateLabelColor: ColorWrapper = ColorWrapper.label
  ) -> ViewConfig {

    var config = ViewConfig()
    config.dateLabelColor = dateLabelColor
    config.lunarDateLabelColor = lunarDateLabelColor

    // Handle out-of-month dates
    if state.dateBelongsTo != .thisMonth {
      config.isSelectedViewHidden = true
      
      // Don't show range views for out-of-month dates (empty dates)
      // This fixes the rendering issue when initial value has empty dates in between
      config.rangeView = RangeViewConfig() // Default hidden state
      
      return config
    }

    config.dateLabelText = state.text

    // Check date constraints
    if let minimumDate = minimumDate, state.date < minimumDate.startOfDay() {
      config.isDateEnabled = false
      return config
    }
    
    if let maximumDate = maximumDate, state.date > maximumDate.endOfDay() {
      config.isDateEnabled = false
      return config
    }

    // Configure selection state
    if state.isSelected {
      // Use custom logic to determine position instead of JTAppleCalendar's selectedPosition()
      let position = determineRangePosition(
        date: state.date,
        rangeValue: rangeValue,
        calendar: calendar
      )
      
      // Only show circle highlight for single selection or range endpoints
      // Middle dates in range should only show range background, not circle
      config.isSelectedViewHidden = (position == .middle)
      
      // Configure range views for non-single selections
      if position != .full {
        config.rangeView = calculateRangeConfig(
          for: position,
          dayOfWeek: state.day.rawValue,
          calendar: calendar
        )
      }
    }

    return config
  }



  /// Custom logic to determine range position instead of relying on JTAppleCalendar
  private static func determineRangePosition(
    date: Date,
    rangeValue: PickerRange?,
    calendar: Calendar
  ) -> SelectionRangePosition {
    guard let range = rangeValue else { return .full }
    
    let dateOnly = date.startOfDay(in: calendar)
    let fromDate = range.fromDate.startOfDay(in: calendar)
    let toDate = range.toDate.startOfDay(in: calendar)
    
    // Same day selection
    if fromDate == toDate {
      return .full
    }
    
    // Normalize range to ensure startDate <= endDate
    let startDate = min(fromDate, toDate)
    let endDate = max(fromDate, toDate)
    
    // Check if current date is one of the endpoints
    if dateOnly == fromDate {
      return .left  // Always treat fromDate as left (start)
    } else if dateOnly == toDate {
      return .right // Always treat toDate as right (end)
    } else if dateOnly > startDate && dateOnly < endDate {
      return .middle // Date is within the normalized range
    } else {
      // Date is outside the range but selected (shouldn't happen in normal flow)
      return .full
    }
  }
  
  private static func calculateRangeConfig(
    for position: SelectionRangePosition,
    dayOfWeek: Int,
    calendar: Calendar
  ) -> RangeViewConfig {
    var config = RangeViewConfig()
    let isFirstDay = dayOfWeek == calendar.firstWeekday
    let isLastDay = dayOfWeek == calendar.lastWeekday
    
    switch position {
    case .left:
      // Start of range: show right side background
      config.rightSideState = isLastDay ? .rounded : .squared
    case .right:
      // End of range: show left side background
      config.leftSideState = isFirstDay ? .rounded : .squared
    case .middle:
      // Middle of range: show both sides
      config.leftSideState = isFirstDay ? .rounded : .squared
      config.rightSideState = isLastDay ? .rounded : .squared
    default:
      // .full - single selection, no range background needed
      break
    }
    
    return config
  }
}

// MARK: - Supporting Types

// Note: CellState.selectedPosition() extension removed as it's no longer needed
// after simplifying the range selection logic.

extension DayCell {
  enum RangeSideState {
    case squared
    case rounded
    case hidden
  }

  struct RangeViewConfig: Hashable {
    var leftSideState: RangeSideState = .hidden
    var rightSideState: RangeSideState = .hidden

    var isHidden: Bool {
      self.leftSideState == .hidden && self.rightSideState == .hidden
    }
  }

  struct ViewConfig {
    var dateLabelText: String?
    var lunarDateLabelText: String?
    var priceLabelText: String?
    var isSelectedViewHidden = true
    var isDateEnabled = true
    var rangeView = RangeViewConfig()
    var dateLabelColor: ColorWrapper = ColorWrapper.label
    var lunarDateLabelColor: ColorWrapper = ColorWrapper.label
    var priceLabelColor: ColorWrapper = ColorWrapper.label
    var dateLabelFontWeight: UIFont.Weight = .regular
  }
}

// MARK: - Configuration Extension

extension PickerConfig {
  public struct DayCell {
    public var dateLabelColor: ColorWrapper = ColorWrapper.customBlack
    public var weekendLabelColor: ColorWrapper = ColorWrapper.customBlack
    public var lunarDateLabelColor: ColorWrapper = ColorWrapper.darkLunarDateColor
    public var specialDateLabelColor: ColorWrapper = ColorWrapper.darkLunarDateColor
    public var rangeBackgroundColor: ColorWrapper = ColorWrapper.customBlack
    public var selectedBackgroundColor: ColorWrapper = ColorWrapper.systemBlue
    public var selectedTextColor: ColorWrapper = ColorWrapper.customWhite
    public var priceLabelColor: ColorWrapper = ColorWrapper.systemBlue
    public var cheapestPriceLabelColor: ColorWrapper = ColorWrapper.systemRed
  }
}
