import {
  Component,
  Input,
  Output,
  EventEmitter,
  ViewChild,
  ElementRef,
  OnInit,
  TemplateRef,
} from '@angular/core';
import { CommonModule } from '@angular/common';

export interface DateRangeValue {
  start: Date | null;
  end: Date | null;
}

@Component({
  selector: 'ccl-date-range-field',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './date-range-field.html',
  styleUrls: ['./date-range-field.css'],
})
export class DateRangeFieldComponent implements OnInit {
  @Input() label = 'From Date - To Date';
  @Input() disabled = false;
  @Input() minSelectableDate?: Date;
  @Input() maxSelectableDate?: Date;
  @Input() startDate: Date | null = null;
  @Input() endDate: Date | null = null;
  @Input() displayTemplate?: TemplateRef<{ range: DateRangeValue }>;

  @Output() rangeChange = new EventEmitter<DateRangeValue>();

  @ViewChild('startPicker', { static: true }) startPicker!: ElementRef<HTMLInputElement>;
  @ViewChild('endPicker', { static: true }) endPicker!: ElementRef<HTMLInputElement>;

  ngOnInit() {
    const today = this.stripTime(new Date());

    if (!this.minSelectableDate) {
      this.minSelectableDate = today;
    }

    if (!this.startDate) {
      this.startDate = today;
    }

    if (!this.endDate) {
      this.endDate = this.startDate;
    }

    this.emitChange();
  }

  openStartPicker(event?: Event) {
    event?.stopPropagation();
    if (this.disabled) return;
    this.startPicker.nativeElement.showPicker?.();
  }

  openEndPicker(event?: Event) {
    event?.stopPropagation();
    if (this.disabled) return;
    this.endPicker.nativeElement.showPicker?.();
  }

  onStartDateChange(event: Event) {
    const input = event.target as HTMLInputElement;
    if (!input.value) {
      this.startDate = null;
      this.emitChange();
      return;
    }

    const parsed = this.clampDate(new Date(input.value));
    this.startDate = parsed;

    if (!this.endDate || this.endDate < this.startDate) {
      this.endDate = this.startDate;
    }

    this.emitChange();

    // Prompt the user to choose the end date next
    setTimeout(() => this.openEndPicker(), 0);
  }

  onEndDateChange(event: Event) {
    const input = event.target as HTMLInputElement;
    if (!input.value) {
      this.endDate = null;
      this.emitChange();
      return;
    }

    let parsed = this.clampDate(new Date(input.value));

    if (this.startDate && parsed < this.startDate) {
      parsed = this.startDate;
    }

    this.endDate = parsed;
    this.emitChange();
  }

  clearRange() {
    if (this.disabled) return;
    this.startDate = null;
    this.endDate = null;
    this.emitChange();
  }

  formatDisplay(date: Date | null): string {
    if (!date) {
      return '--/--/----';
    }
    return new Intl.DateTimeFormat('en-US', {
      month: '2-digit',
      day: '2-digit',
      year: 'numeric',
    }).format(date);
  }

  getRangeText(): string {
    return `${this.formatDisplay(this.startDate)} - ${this.formatDisplay(this.endDate)}`;
  }

  getMinDateString(): string {
    return this.minSelectableDate ? this.toInputValue(this.minSelectableDate) : '';
  }

  getMaxDateString(): string {
    return this.maxSelectableDate ? this.toInputValue(this.maxSelectableDate) : '';
  }

  private emitChange() {
    this.rangeChange.emit({
      start: this.startDate,
      end: this.endDate,
    });
  }

  private clampDate(value: Date): Date {
    const stripped = this.stripTime(value);
    if (this.minSelectableDate && stripped < this.minSelectableDate) {
      return this.minSelectableDate;
    }
    if (this.maxSelectableDate && stripped > this.maxSelectableDate) {
      return this.maxSelectableDate;
    }
    return stripped;
  }

  private stripTime(value: Date): Date {
    return new Date(value.getFullYear(), value.getMonth(), value.getDate());
  }

  private toInputValue(date: Date): string {
    return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
      .getDate()
      .toString()
      .padStart(2, '0')}`;
  }
}

