import {
  ChangeDetectionStrategy,
  Component,
  effect,
  inject,
  untracked,
} from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { toSignal } from '@angular/core/rxjs-interop';
import { DateInputDirective } from './date-input.directive';
import { RangeDatepicker } from '../../range-datepicker';
import { dateBoundsValidator } from '../../validators/date-bounds.validator';
import { dateRangeStartStopOrderValidator } from '../../validators/date-range-order.validator';

/**
 * SelectedRangeComponent
 *
 * A UI component for selecting a date range.
 * It synchronizes form controls with the underlying RangeDatepicker,
 * ensuring that selected dates are within permitted bounds and that the start date
 * precedes the stop date.
 */
@Component({
  selector: 'ui-selected-range',
  templateUrl: 'selected-range.component.html',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    '[class]': "['ui-selected-range']",
  },
  imports: [ReactiveFormsModule, DateInputDirective],
})
export class SelectedRangeComponent {
  rangeDatepicker = inject(RangeDatepicker);

  /**
   * Creates and returns a reactive form with 'start' and 'stop' form controls.
   * Each control is set up with validators to ensure the dates are within bounds.
   *
   * @returns {FormGroup} The form group containing the date controls.
   */
  createForm() {
    const value = this.rangeDatepicker.value();

    return new FormGroup(
      {
        start: new FormControl(value?.[0], [
          dateBoundsValidator(
            this.rangeDatepicker.min(),
            this.rangeDatepicker.max(),
          ),
        ]),
        stop: new FormControl(value?.[1], [
          dateBoundsValidator(
            this.rangeDatepicker.min(),
            this.rangeDatepicker.max(),
          ),
        ]),
      },
      {
        validators: dateRangeStartStopOrderValidator('start', 'stop'),
      },
    );
  }

  /** The reactive form instance managing selected date range values. */
  form: ReturnType<typeof this.createForm> = this.createForm();

  /** Shortcut to access the 'start' FormControl of the form. */
  start = this.form.controls['start'];

  /** Shortcut to access the 'stop' FormControl of the form. */
  stop = this.form.controls['stop'];

  /**
   * A signal representing the form's value changes.
   * Updates whenever the form's values change.
   */
  valueChanges = toSignal(this.form.valueChanges);

  /**
   * Effect to patch form values when the RangeDatepicker's value changes.
   * If no value is provided, the form gets reset.
   */
  patchFormValuesEffectFn = effect(() => {
    const value = this.rangeDatepicker.value();

    if (!value) {
      this.form.reset();
      return;
    }

    untracked(() => {
      const [start, stop] = value;
      this.form.patchValue({ start, stop }, { emitEvent: false });
    });
  });

  /**
   * Effect to update the RangeDatepicker's value based on the form's current valid state.
   * It triggers on form value changes and only sets the datepicker's value if the form
   * and its controls are valid.
   */
  setDatepickerValueEffectFn = effect(() => {
    this.valueChanges();
    untracked(() => {
      if (this.form.valid && this.start.valid && this.stop.valid) {
        this.rangeDatepicker.setValue([
          this.start.value ?? undefined,
          this.stop.value ?? undefined,
        ]);
      }
    });
  });
}
