import { afterEach, describe, expect, it, vi } from 'vitest';
import { WebSocket } from 'ws';

import { COMMAND_REGISTRY } from '../../src/handlers/index.js';
import { MessageDispatcher } from '../../src/server/MessageDispatcher.js';
import { Person } from '../../src/models/Person.js';
import { Player } from '../../src/models/Player.js';
import { PlayerSession } from '../../src/game/PlayerSession.js';
import { setEventRuntimeForTesting } from '../../src/events/v2/runtime.js';

function createTestPlayer(): Player {
  const character = new Person({
    id: 'player-char',
    firstname: 'Test',
    lastname: 'Player',
    sex: 'Male',
    ageYears: 22,
    money: 5000,
    diamonds: 50,
    energy: 100,
    happiness: 60,
    social: 60,
  });

  return new Player({
    userId: 'user-1',
    character,
    status: 'playing',
    date: '2026-02-07',
    hourOfDay: 10,
    gameSpeed: 1,
  });
}

afterEach(() => {
  setEventRuntimeForTesting(null);
});

describe('events v2 dispatch integration', () => {
  it('routes eventResponse command to v2 responder', async () => {
    const runtime = {
      promptNext: vi.fn().mockResolvedValue(null),
      respond: vi.fn().mockResolvedValue({
        type: 'event_resolved',
        eventId: 'event_adult',
        instanceId: 'evt-inst-1',
        resolutionText: 'Resolved',
      }),
    };
    setEventRuntimeForTesting(runtime as never);

    const dispatcher = new MessageDispatcher();
    dispatcher.registerAll(COMMAND_REGISTRY);

    const session = {
      player: createTestPlayer(),
      send: vi.fn(),
      sendPlayerObject: vi.fn(),
    };

    await dispatcher.dispatch(
      'eventResponse',
      { eventId: 'event_adult', choiceId: 'choice_1' },
      session as unknown as PlayerSession
    );

    expect(runtime.respond).toHaveBeenCalledWith(session.player, {
      eventId: 'event_adult',
      choiceId: 'choice_1',
    });
    expect(session.send).toHaveBeenCalledWith(
      expect.objectContaining({
        type: 'event_resolved',
        eventId: 'event_adult',
      })
    );
  });

  it('emits v2 event_prompt envelope from the session loop', async () => {
    const runtime = {
      promptNext: vi.fn().mockResolvedValue({
        type: 'event_prompt',
        eventId: 'event_adult',
        instanceId: 'evt-inst-1',
        prompt: 'Adult prompt',
        choices: [{ choiceId: 'choice_1', text: 'Choose this' }],
      }),
      respond: vi.fn(),
    };
    setEventRuntimeForTesting(runtime as never);

    const sentMessages: unknown[] = [];
    const ws = {
      readyState: WebSocket.OPEN,
      send: vi.fn((payload: string) => {
        sentMessages.push(JSON.parse(payload));
      }),
    };

    const session = new PlayerSession(ws as unknown as WebSocket, createTestPlayer());

    await (session as any).processHourTick();

    expect(sentMessages).toContainEqual(
      expect.objectContaining({
        type: 'event_prompt',
        eventId: 'event_adult',
        instanceId: 'evt-inst-1',
      })
    );
  });
});
