/**
 * Event Registry with condition-based indexing
 * Replaces O(n) event scanning with O(1) filtered lookups
 * Ported from Python event_registry.py
 *
 * @deprecated Active event runtime is events/v2 registry + engine.
 * This file remains for compatibility paths and characterization coverage.
 */

import { Player } from '../../models/index.js';
import { EventResult, type EventMode } from '../../events/base.js';

/**
 * Event function signature
 */
export type RegisteredEventFunction = (
  player: Player,
  type?: 'message' | 'question' | 'answer' | 'check'
) => EventResult;

/**
 * Event registration info
 */
export interface EventInfo {
  id: string;
  func: RegisteredEventFunction;
  ageRange?: [number, number];
  requiresRelationship?: boolean;
  requiresJob?: boolean;
  dayOfYear?: number;
  mode?: EventMode;
}

/**
 * Event Registry - manages events with efficient filtering
 *
 * Events can be registered with conditions:
 * - ageRange: [minAge, maxAge]
 * - requiresRelationship: needs relationships to trigger
 * - requiresJob: needs player to have a job
 * - dayOfYear: specific day of year (1-365)
 */
export class EventRegistry {
  private _events: Map<string, EventInfo> = new Map();
  private _byAge: Map<string, string[]> = new Map(); // "min-max" -> [eventIds]
  private _noConditions: string[] = [];

  /**
   * Register an event with optional conditions
   */
  register(
    eventId: string,
    func: RegisteredEventFunction,
    options: {
      ageRange?: [number, number];
      requiresRelationship?: boolean;
      requiresJob?: boolean;
      dayOfYear?: number;
      mode?: EventMode;
    } = {}
  ): void {
    if (this._events.has(eventId)) {
      console.debug(`Event ${eventId} already registered, skipping duplicate`);
      return;
    }

    const eventInfo: EventInfo = {
      id: eventId,
      func,
      ...options,
    };

    this._events.set(eventId, eventInfo);

    // Index by age range
    if (options.ageRange) {
      const key = `${options.ageRange[0]}-${options.ageRange[1]}`;
      if (!this._byAge.has(key)) {
        this._byAge.set(key, []);
      }
      this._byAge.get(key)!.push(eventId);
    }

    // If no conditions, always check
    if (
      !options.ageRange &&
      !options.requiresRelationship &&
      !options.requiresJob &&
      !options.dayOfYear
    ) {
      this._noConditions.push(eventId);
    }

    console.debug(`Registered event: ${eventId}`);
  }

  /**
   * Get events applicable to player's current state
   */
  getApplicableEvents(player: Player): EventInfo[] {
    const applicable: EventInfo[] = [];
    const playerAge = player.c.ageYears ?? 0;
    const playerDay = player.dayOfYear ?? 0;
    const hasRelationships = (player.r ?? []).length > 0;
    const hasJob = Boolean(player.c.occupation && player.c.occupation !== 'none');

    // Check age-based events
    for (const [ageKey, eventIds] of this._byAge) {
      const [minAge, maxAge] = ageKey.split('-').map(Number);
      if (playerAge >= minAge && playerAge <= maxAge) {
        for (const eventId of eventIds) {
          if (!player.events.has(eventId)) {
            const eventInfo = this._events.get(eventId);
            if (!eventInfo) continue;

            // Check other conditions
            if (eventInfo.requiresRelationship && !hasRelationships) continue;
            if (eventInfo.requiresJob && !hasJob) continue;
            if (eventInfo.dayOfYear && eventInfo.dayOfYear !== playerDay) continue;

            applicable.push(eventInfo);
          }
        }
      }
    }

    // Check unconditional events
    for (const eventId of this._noConditions) {
      if (!player.events.has(eventId)) {
        const eventInfo = this._events.get(eventId);
        if (eventInfo) {
          applicable.push(eventInfo);
        }
      }
    }

    return applicable;
  }

  /**
   * Get number of registered events
   */
  count(): number {
    return this._events.size;
  }

  /**
   * List all registered event IDs
   */
  listEvents(): string[] {
    return Array.from(this._events.keys());
  }

  /**
   * Clear all registered events
   */
  clear(): void {
    this._events.clear();
    this._byAge.clear();
    this._noConditions = [];
  }
}

// Global registry instance
const _registry = new EventRegistry();

/**
 * Register an event in the global registry
 */
export function registerEvent(
  eventId: string,
  func: RegisteredEventFunction,
  options?: {
    ageRange?: [number, number];
    requiresRelationship?: boolean;
    requiresJob?: boolean;
    dayOfYear?: number;
    mode?: EventMode;
  }
): void {
  _registry.register(eventId, func, options);
}

/**
 * Get applicable events from global registry
 */
export function getApplicableEvents(player: Player): EventInfo[] {
  return _registry.getApplicableEvents(player);
}

/**
 * Get total registered event count
 */
export function eventCount(): number {
  return _registry.count();
}

/**
 * Get the global registry instance
 */
export function getEventRegistry(): EventRegistry {
  return _registry;
}
