import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, forwardRef, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
import { faCalendarDays, faTimes, faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';

export type DatePickerSize = 'sm' | 'md' | 'lg';
export type DatePickerVariant = 'outlined' | 'filled' | 'underlined';
export type DatePickerState = 'default' | 'error' | 'success' | 'warning';

@Component({
  selector: 'ui-date-picker',
  standalone: true,
  imports: [CommonModule, FontAwesomeModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DatePickerComponent),
      multi: true
    }
  ],
  template: `
    <div class="ui-date-picker" [class]="getWrapperClasses()">
      <!-- Label -->
      @if (label) {
        <label 
          class="ui-date-picker__label"
          [for]="inputId"
          [class.ui-date-picker__label--required]="required"
        >
          {{ label }}
          @if (required) {
            <span class="ui-date-picker__required-indicator">*</span>
          }
        </label>
      }
      
      <!-- Input Container -->
      <div class="ui-date-picker__container" [class]="getContainerClasses()">
        <!-- Calendar Icon -->
        <div class="ui-date-picker__prefix-icon">
          <fa-icon [icon]="faCalendarDays"></fa-icon>
        </div>
        
        <!-- Input Field -->
        <input
          [id]="inputId"
          class="ui-date-picker__field"
          type="text"
          [placeholder]="placeholder"
          [disabled]="disabled"
          [readonly]="true"
          [required]="required"
          [value]="formattedValue"
          [attr.aria-expanded]="isOpen()"
          [attr.aria-haspopup]="'dialog'"
          [attr.aria-describedby]="helperText ? inputId + '-helper' : null"
          (click)="toggleCalendar()"
          (keydown)="onInputKeyDown($event)"
        />
        
        <!-- Clear Button -->
        @if (clearable && value && !disabled) {
          <button
            type="button"
            class="ui-date-picker__clear-btn"
            (click)="clearValue()"
            [attr.aria-label]="'Clear ' + (label || 'date')"
          >
            <fa-icon [icon]="faTimes"></fa-icon>
          </button>
        }
      </div>
      
      <!-- Calendar Dropdown -->
      @if (isOpen()) {
        <div class="ui-date-picker__dropdown" role="dialog" aria-label="Calendar">
          <!-- Calendar Header -->
          <div class="ui-date-picker__header">
            <button
              type="button"
              class="ui-date-picker__nav-btn"
              (click)="previousMonth()"
              [attr.aria-label]="'Previous month'"
            >
              <fa-icon [icon]="faChevronLeft"></fa-icon>
            </button>
            
            <div class="ui-date-picker__month-year">
              <button
                type="button"
                class="ui-date-picker__month-btn"
                (click)="toggleMonthView()"
              >
                {{ getMonthYearLabel() }}
              </button>
            </div>
            
            <button
              type="button"
              class="ui-date-picker__nav-btn"
              (click)="nextMonth()"
              [attr.aria-label]="'Next month'"
            >
              <fa-icon [icon]="faChevronRight"></fa-icon>
            </button>
          </div>
          
          <!-- Calendar Content -->
          @if (!showMonthView()) {
            <!-- Days Grid -->
            <div class="ui-date-picker__calendar">
              <!-- Day Headers -->
              <div class="ui-date-picker__day-headers">
                @for (day of dayHeaders; track day) {
                  <div class="ui-date-picker__day-header">{{ day }}</div>
                }
              </div>
              
              <!-- Days Grid -->
              <div class="ui-date-picker__days">
                @for (day of calendarDays; track day.date.getTime()) {
                  <button
                    type="button"
                    class="ui-date-picker__day"
                    [class.ui-date-picker__day--today]="day.isToday"
                    [class.ui-date-picker__day--selected]="day.isSelected"
                    [class.ui-date-picker__day--other-month]="day.isOtherMonth"
                    [class.ui-date-picker__day--disabled]="day.isDisabled"
                    [disabled]="day.isDisabled"
                    [attr.aria-label]="getDayAriaLabel(day)"
                    [attr.aria-selected]="day.isSelected"
                    (click)="selectDate(day.date)"
                  >
                    {{ day.date.getDate() }}
                  </button>
                }
              </div>
            </div>
          } @else {
            <!-- Month/Year Selection -->
            <div class="ui-date-picker__month-year-picker">
              <div class="ui-date-picker__months">
                @for (month of months; track month.value) {
                  <button
                    type="button"
                    class="ui-date-picker__month-option"
                    [class.ui-date-picker__month-option--selected]="month.value === currentMonth()"
                    (click)="selectMonth(month.value)"
                  >
                    {{ month.label }}
                  </button>
                }
              </div>
              
              <div class="ui-date-picker__year-input">
                <input
                  type="number"
                  class="ui-date-picker__year-field"
                  [value]="currentYear()"
                  (input)="onYearInput($event)"
                  [min]="minYear"
                  [max]="maxYear"
                />
              </div>
            </div>
          }
        </div>
      }
      
      <!-- Helper Text / Error Message -->
      @if (helperText || errorMessage) {
        <div 
          class="ui-date-picker__helper-text" 
          [class]="getHelperTextClasses()"
          [id]="inputId + '-helper'"
        >
          {{ state === 'error' ? errorMessage : helperText }}
        </div>
      }
    </div>
  `,
  styleUrl: './date-picker.component.scss'
})
export class DatePickerComponent implements ControlValueAccessor {
  @Input() label: string = '';
  @Input() placeholder: string = 'Select date';
  @Input() size: DatePickerSize = 'md';
  @Input() variant: DatePickerVariant = 'outlined';
  @Input() state: DatePickerState = 'default';
  @Input() disabled = false;
  @Input() required = false;
  @Input() clearable = true;
  @Input() helperText: string = '';
  @Input() errorMessage: string = '';
  @Input() minDate: Date | null = null;
  @Input() maxDate: Date | null = null;
  @Input() dateFormat: string = 'MM/dd/yyyy';
  @Input() inputId: string = `date-picker-${Math.random().toString(36).substr(2, 9)}`;

  @Output() dateChange = new EventEmitter<Date | null>();
  @Output() calendarOpen = new EventEmitter<void>();
  @Output() calendarClose = new EventEmitter<void>();

  value: Date | null = null;
  isOpen = signal(false);
  currentMonth = signal(new Date().getMonth());
  currentYear = signal(new Date().getFullYear());
  showMonthView = signal(false);

  readonly faCalendarDays = faCalendarDays;
  readonly faTimes = faTimes;
  readonly faChevronLeft = faChevronLeft;
  readonly faChevronRight = faChevronRight;

  readonly dayHeaders = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
  readonly months = [
    { value: 0, label: 'January' },
    { value: 1, label: 'February' },
    { value: 2, label: 'March' },
    { value: 3, label: 'April' },
    { value: 4, label: 'May' },
    { value: 5, label: 'June' },
    { value: 6, label: 'July' },
    { value: 7, label: 'August' },
    { value: 8, label: 'September' },
    { value: 9, label: 'October' },
    { value: 10, label: 'November' },
    { value: 11, label: 'December' }
  ];

  readonly minYear = 1900;
  readonly maxYear = 2100;

  private onChange = (value: Date | null) => {};
  private onTouched = () => {};

  writeValue(value: Date | null): void {
    this.value = value;
    if (value) {
      this.currentMonth.set(value.getMonth());
      this.currentYear.set(value.getFullYear());
    }
  }

  registerOnChange(fn: (value: Date | null) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  get formattedValue(): string {
    if (!this.value) return '';
    return this.formatDate(this.value);
  }

  get calendarDays() {
    const year = this.currentYear();
    const month = this.currentMonth();
    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    const startDate = new Date(firstDay);
    startDate.setDate(startDate.getDate() - firstDay.getDay());
    
    const days = [];
    const currentDate = new Date(startDate);
    
    for (let i = 0; i < 42; i++) {
      const isOtherMonth = currentDate.getMonth() !== month;
      const isToday = this.isSameDay(currentDate, new Date());
      const isSelected = this.value ? this.isSameDay(currentDate, this.value) : false;
      const isDisabled = this.isDateDisabled(currentDate);
      
      days.push({
        date: new Date(currentDate),
        isOtherMonth,
        isToday,
        isSelected,
        isDisabled
      });
      
      currentDate.setDate(currentDate.getDate() + 1);
    }
    
    return days;
  }

  getWrapperClasses(): string {
    const classes = [
      `ui-date-picker--${this.size}`,
      `ui-date-picker--${this.variant}`,
      `ui-date-picker--${this.state}`
    ];

    if (this.disabled) classes.push('ui-date-picker--disabled');
    if (this.isOpen()) classes.push('ui-date-picker--open');

    return classes.join(' ');
  }

  getContainerClasses(): string {
    const classes: string[] = [];
    if (this.clearable && this.value) classes.push('ui-date-picker__container--has-clear');
    return classes.join(' ');
  }

  getHelperTextClasses(): string {
    return `ui-date-picker__helper-text--${this.state}`;
  }

  getMonthYearLabel(): string {
    const monthName = this.months[this.currentMonth()].label;
    return `${monthName} ${this.currentYear()}`;
  }

  getDayAriaLabel(day: any): string {
    const date = day.date;
    const dayName = date.toLocaleDateString('en-US', { weekday: 'long' });
    const monthName = date.toLocaleDateString('en-US', { month: 'long' });
    return `${dayName}, ${monthName} ${date.getDate()}, ${date.getFullYear()}`;
  }

  toggleCalendar(): void {
    if (this.disabled) return;
    
    if (this.isOpen()) {
      this.closeCalendar();
    } else {
      this.openCalendar();
    }
  }

  openCalendar(): void {
    this.isOpen.set(true);
    this.calendarOpen.emit();
  }

  closeCalendar(): void {
    this.isOpen.set(false);
    this.showMonthView.set(false);
    this.onTouched();
    this.calendarClose.emit();
  }

  toggleMonthView(): void {
    this.showMonthView.set(!this.showMonthView());
  }

  previousMonth(): void {
    if (this.currentMonth() === 0) {
      this.currentMonth.set(11);
      this.currentYear.set(this.currentYear() - 1);
    } else {
      this.currentMonth.set(this.currentMonth() - 1);
    }
  }

  nextMonth(): void {
    if (this.currentMonth() === 11) {
      this.currentMonth.set(0);
      this.currentYear.set(this.currentYear() + 1);
    } else {
      this.currentMonth.set(this.currentMonth() + 1);
    }
  }

  selectMonth(month: number): void {
    this.currentMonth.set(month);
    this.showMonthView.set(false);
  }

  selectDate(date: Date): void {
    if (this.isDateDisabled(date)) return;
    
    this.value = new Date(date);
    this.onChange(this.value);
    this.dateChange.emit(this.value);
    this.closeCalendar();
  }

  clearValue(): void {
    this.value = null;
    this.onChange(null);
    this.dateChange.emit(null);
  }

  onInputKeyDown(event: KeyboardEvent): void {
    if (event.key === 'Enter' || event.key === ' ') {
      event.preventDefault();
      this.toggleCalendar();
    } else if (event.key === 'Escape' && this.isOpen()) {
      event.preventDefault();
      this.closeCalendar();
    }
  }

  onYearInput(event: Event): void {
    const target = event.target as HTMLInputElement;
    const year = parseInt(target.value, 10);
    
    if (!isNaN(year) && year >= this.minYear && year <= this.maxYear) {
      this.currentYear.set(year);
    }
  }

  private formatDate(date: Date): string {
    // Simple MM/dd/yyyy format - can be enhanced based on dateFormat input
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const day = date.getDate().toString().padStart(2, '0');
    const year = date.getFullYear();
    return `${month}/${day}/${year}`;
  }

  private isSameDay(date1: Date, date2: Date): boolean {
    return date1.getDate() === date2.getDate() &&
           date1.getMonth() === date2.getMonth() &&
           date1.getFullYear() === date2.getFullYear();
  }

  private isDateDisabled(date: Date): boolean {
    if (this.minDate && date < this.minDate) return true;
    if (this.maxDate && date > this.maxDate) return true;
    return false;
  }
}