/**
 * OutputCollector - Collects game output for testing
 *
 * Implements IGameOutput interface to capture events, questions,
 * and player updates instead of sending them via WebSocket.
 */

import type { IGameOutput, GameEvent } from '../game/engine/GameEngine.js';
import type { Player } from '../models/index.js';

export interface CollectedEvent {
  timestamp: Date;
  event: GameEvent;
}

export interface CollectedQuestion {
  timestamp: Date;
  id: string;
  message: string;
  answers: Array<{ option: string; data?: string }>;
  pending: boolean;
}

export interface CollectedUpdate {
  timestamp: Date;
  data: Record<string, unknown>;
}

export class OutputCollector implements IGameOutput {
  events: CollectedEvent[] = [];
  questions: CollectedQuestion[] = [];
  playerUpdates: Player[] = [];
  dictUpdates: CollectedUpdate[] = [];

  async sendEventMessage(event: GameEvent): Promise<void> {
    if (event.type === 'questionEvent') {
      this.questions.push({
        timestamp: new Date(),
        id: event.id,
        message: event.message,
        answers: (event as Record<string, unknown>).answers as Array<{
          option: string;
          data?: string;
        }> ?? [],
        pending: true,
      });
    } else {
      this.events.push({
        timestamp: new Date(),
        event,
      });
    }
  }

  async sendUserInfo(player: Player): Promise<void> {
    this.playerUpdates.push(player);
  }

  async sendDict(data: Record<string, unknown>): Promise<void> {
    this.dictUpdates.push({
      timestamp: new Date(),
      data,
    });
  }

  // Query methods
  getEvents(): CollectedEvent[] {
    return [...this.events];
  }

  getQuestions(): CollectedQuestion[] {
    return [...this.questions];
  }

  getPendingQuestions(): CollectedQuestion[] {
    return this.questions.filter((q) => q.pending);
  }

  getLastEvent(): CollectedEvent | undefined {
    return this.events[this.events.length - 1];
  }

  getLastQuestion(): CollectedQuestion | undefined {
    return this.questions[this.questions.length - 1];
  }

  hasEventWithId(id: string): boolean {
    return this.events.some((e) => e.event.id === id);
  }

  hasEventWithText(text: string): boolean {
    return this.events.some((e) => e.event.message.includes(text));
  }

  markQuestionAnswered(questionId: string): void {
    const q = this.questions.find((q) => q.id === questionId);
    if (q) q.pending = false;
  }

  clear(): void {
    this.events = [];
    this.questions = [];
    this.playerUpdates = [];
    this.dictUpdates = [];
  }

  getStats(): Record<string, number> {
    return {
      events: this.events.length,
      questions: this.questions.length,
      pendingQuestions: this.getPendingQuestions().length,
      playerUpdates: this.playerUpdates.length,
      dictUpdates: this.dictUpdates.length,
    };
  }
}
