import { randomUUID } from 'crypto';
import type { HookAction, HookResult, PendingConfirmation, HookConfig } from './types.js';

export type InteractiveConfirmer = (pending: {
  id: string;
  tool: string;
  args: Record<string, unknown>;
}) => Promise<HookResult>;

export class HookEngine {
  private confirmPatterns: RegExp[];
  private logPatterns: RegExp[];
  private pendingConfirmations: Map<string, PendingConfirmation> = new Map();
  private interactiveConfirmer?: InteractiveConfirmer;

  constructor(config: HookConfig) {
    this.confirmPatterns = config.confirm.map(p => this.patternToRegex(p));
    this.logPatterns = config.log.map(p => this.patternToRegex(p));
  }

  /**
   * Optional interactive confirmation handler.
   * When set, confirmation requests are handled immediately (no pending queue).
   * Useful for CLI/TUI environments where we can prompt the user inline.
   */
  setInteractiveConfirmer(confirmer: InteractiveConfirmer | undefined): void {
    this.interactiveConfirmer = confirmer;
  }

  private patternToRegex(pattern: string): RegExp {
    const escaped = pattern
      .replace(/[.+^${}()|[\]\\]/g, '\\$&')
      .replace(/\*/g, '.*');
    return new RegExp(`^${escaped}$`);
  }

  getAction(tool: string): HookAction {
    if (this.confirmPatterns.some(p => p.test(tool))) {
      return 'confirm';
    }
    if (this.logPatterns.some(p => p.test(tool))) {
      return 'log';
    }
    return 'silent';
  }

  async requestConfirmation(tool: string, args: Record<string, unknown>): Promise<HookResult> {
    const id = randomUUID();

    if (this.interactiveConfirmer) {
      return await this.interactiveConfirmer({ id, tool, args });
    }

    return new Promise((resolve) => {
      const pending: PendingConfirmation = {
        id,
        tool,
        args,
        resolve,
        createdAt: new Date(),
      };
      this.pendingConfirmations.set(id, pending);
    });
  }

  resolveConfirmation(id: string, result: HookResult): boolean {
    const pending = this.pendingConfirmations.get(id);
    if (!pending) {
      return false;
    }

    pending.resolve(result);
    this.pendingConfirmations.delete(id);
    return true;
  }

  getPendingConfirmations(): PendingConfirmation[] {
    return Array.from(this.pendingConfirmations.values());
  }

  clearExpiredConfirmations(maxAgeMs: number = 5 * 60 * 1000): number {
    const now = Date.now();
    let cleared = 0;

    for (const [id, pending] of this.pendingConfirmations) {
      if (now - pending.createdAt.getTime() > maxAgeMs) {
        pending.resolve({ approved: false, reason: 'Confirmation timed out' });
        this.pendingConfirmations.delete(id);
        cleared++;
      }
    }

    return cleared;
  }
}
