/**
 * Value Object: AlertSeverity
 *
 * Encapsulates the severity level of a compliance alert.
 * Immutable after creation via static factory methods.
 */
export enum SeverityLevel {
  LOW = 'low',
  MEDIUM = 'medium',
  HIGH = 'high',
  CRITICAL = 'critical',
}

export class AlertSeverity {
  private static readonly VALID_LEVELS = Object.values(SeverityLevel);

  private constructor(private readonly level: SeverityLevel) {}

  /**
   * Create an AlertSeverity from a string level.
   * @throws Error if level is not a valid severity level
   */
  static create(level: string): AlertSeverity {
    const normalized = level.toLowerCase() as SeverityLevel;
    if (!AlertSeverity.VALID_LEVELS.includes(normalized)) {
      throw new Error(
        `Invalid severity level: "${level}". Must be one of: ${AlertSeverity.VALID_LEVELS.join(', ')}`,
      );
    }
    return new AlertSeverity(normalized);
  }

  /** Create a LOW severity */
  static low(): AlertSeverity {
    return new AlertSeverity(SeverityLevel.LOW);
  }

  /** Create a MEDIUM severity */
  static medium(): AlertSeverity {
    return new AlertSeverity(SeverityLevel.MEDIUM);
  }

  /** Create a HIGH severity */
  static high(): AlertSeverity {
    return new AlertSeverity(SeverityLevel.HIGH);
  }

  /** Create a CRITICAL severity */
  static critical(): AlertSeverity {
    return new AlertSeverity(SeverityLevel.CRITICAL);
  }

  /**
   * Derive severity from a risk score.
   * - 0-39: LOW
   * - 40-69: MEDIUM
   * - 70-89: HIGH
   * - 90-100: CRITICAL
   */
  static fromRiskScore(score: number): AlertSeverity {
    if (score >= 90) return AlertSeverity.critical();
    if (score >= 70) return AlertSeverity.high();
    if (score >= 40) return AlertSeverity.medium();
    return AlertSeverity.low();
  }

  get value(): SeverityLevel {
    return this.level;
  }

  toString(): string {
    return this.level;
  }

  /** Numeric priority (higher = more severe) for sorting/comparison */
  get priority(): number {
    switch (this.level) {
      case SeverityLevel.CRITICAL:
        return 4;
      case SeverityLevel.HIGH:
        return 3;
      case SeverityLevel.MEDIUM:
        return 2;
      case SeverityLevel.LOW:
        return 1;
    }
  }

  isHigherThan(other: AlertSeverity): boolean {
    return this.priority > other.priority;
  }

  isAtLeast(level: SeverityLevel): boolean {
    return this.priority >= AlertSeverity.create(level).priority;
  }

  equals(other: AlertSeverity): boolean {
    return this.level === other.level;
  }
}
