/**
 * Event auth errors — typed failures for cross-product event verification.
 *
 * ADR-ECO-017: verifyEvent throws typed errors for each failure mode.
 * Consumers MUST catch and handle these explicitly (no silent ignore).
 *
 * @module auth/errors
 * @public
 */

/** Thrown when the event's HMAC signature does not match the recomputed value. */
export class InvalidSignatureError extends Error {
  constructor(message = "Event signature is invalid") {
    super(message);
    this.name = "InvalidSignatureError";
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

/**
 * Thrown when the event timestamp is outside the acceptable clock skew window.
 * Default window: 5 minutes (±300 000 ms).
 */
export class ClockSkewError extends Error {
  readonly skewMs: number;
  constructor(skewMs: number) {
    super(
      `Event timestamp skew (${skewMs}ms) exceeds the allowed window. Possible replay or clock drift.`
    );
    this.name = "ClockSkewError";
    this.skewMs = skewMs;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

/**
 * Thrown when the nonce (idempotencyKey) has already been seen within the TTL window.
 * Indicates a replay attack or duplicate delivery.
 */
export class ReplayDetectedError extends Error {
  readonly idempotencyKey: string;
  constructor(idempotencyKey: string) {
    super(
      `Replay detected: idempotencyKey "${idempotencyKey}" has already been processed within the nonce TTL window.`
    );
    this.name = "ReplayDetectedError";
    this.idempotencyKey = idempotencyKey;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

/**
 * Thrown when the event's source field is not in the allowed enum.
 * Allowed sources: forge | vauban | vauban-finance | brain | citadel | glacis | cc | tenant
 */
export class UnknownSourceError extends Error {
  readonly source: string;
  constructor(source: string) {
    super(
      `Unknown event source: "${source}". Must be one of: forge, vauban, vauban-finance, brain, citadel, glacis, cc, tenant.`
    );
    this.name = "UnknownSourceError";
    this.source = source;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}
