import { Directive } from '@angular/core';
import { isBefore } from 'date-fns';
import { DatepickerBase } from './datepicker-base';
import { DateRangeValue, DateRangeSchema } from './types';

/**
 * Directive for a date range picker extending the DatepickerBase functionality.
 * Allows parsing and setting of date range values with proper ordering.
 */
@Directive()
export class RangeDatepicker extends DatepickerBase<DateRangeValue> {
  /**
   * Parses an unknown value into a DateRangeValue using the DateRangeSchema.
   *
   * @param value - The value to be parsed.
   * @returns The parsed DateRangeValue or undefined if parsing fails.
   */
  parseValue(value: unknown): DateRangeValue | undefined {
    return DateRangeSchema.optional().parse(value);
  }

  /**
   * Sets the date range based on the provided date.
   * Determines whether to assign the date as the start or end value,
   * while ensuring the start date is less than the end date.
   *
   * @param value - The date to be set in the range.
   */
  setDateRange(value: Date) {
    const currentValue = this.value();

    if (!Array.isArray(currentValue) || currentValue.every((v) => !!v)) {
      this.setValue([value, undefined]);
    }
    // Set start value when only end value is present and ensure start < end
    else if (!currentValue[0]) {
      this.setValue(this.sortRangeValuesAsc([value, currentValue[1]]));
    }
    // Set end value when only start value is present and ensure start < end
    else {
      this.setValue(this.sortRangeValuesAsc([currentValue[0], value]));
    }
  }

  /**
   * Sorts the provided date range values in ascending order.
   * If either start or end is missing, returns the original range.
   * Uses date-fns isBefore function to compare dates.
   *
   * @param rangeValues - An array with two dates representing the start and end.
   * @returns The sorted date range in ascending order.
   */
  sortRangeValuesAsc(rangeValues: DateRangeValue): DateRangeValue {
    const [start, end] = rangeValues;

    if (!start || !end) {
      return rangeValues;
    }

    return isBefore(end, start) ? [end, start] : [start, end];
  }
}
