import type { IValueObject } from '@core/shared/domain';
import { NotificationDomainError } from '../errors/NotificationDomainError';

export interface QuietHoursProps {
  startHour: number;
  endHour: number;
}

/**
 * Value Object: QuietHours
 *
 * Encapsulates a daily quiet-hours window using 0-23 hour indices and
 * provides logic to determine whether a given hour falls within the window.
 *
 * Supports both normal ranges (start < end) and overnight ranges (start > end).
 */
export class QuietHours implements IValueObject<QuietHoursProps> {
  public readonly props: QuietHoursProps;

  private constructor(startHour: number, endHour: number) {
    this.props = { startHour, endHour };
  }

  /**
   * Factory with validation.
   * - Hours must be integers between 0 and 23.
   * - Start and end cannot be equal (would mean a 0-length window).
   */
  static create(startHour: number, endHour: number): QuietHours {
    QuietHours.assertValidHour(startHour, 'Start hour');
    QuietHours.assertValidHour(endHour, 'End hour');

    if (startHour === endHour) {
      throw new NotificationDomainError('Quiet hours start and end cannot be the same', 'validation');
    }

    return new QuietHours(startHour, endHour);
  }

  private static assertValidHour(value: number, label: string): void {
    if (!Number.isInteger(value)) {
      throw new NotificationDomainError(`${label} must be an integer between 0 and 23`, 'validation');
    }
    if (value < 0 || value > 23) {
      throw new NotificationDomainError(`${label} must be between 0 and 23`, 'validation');
    }
  }

  /**
   * Returns true if the given hour (0-23) lies within the quiet window.
   */
  containsHour(hour: number): boolean {
    QuietHours.assertValidHour(hour, 'Hour');

    const { startHour, endHour } = this.props;

    if (startHour < endHour) {
      // Normal range (e.g., 22:00 to 23:59 is NOT this case, but 1:00 to 7:00 is)
      return hour >= startHour && hour < endHour;
    }

    // Overnight range (e.g., 22:00 to 07:00)
    return hour >= startHour || hour < endHour;
  }

  equals(other: IValueObject<QuietHoursProps>): boolean {
    return (
      this.props.startHour === other.props.startHour &&
      this.props.endHour === other.props.endHour
    );
  }
}