import { describe, expect, it } from 'vitest';

import {
  buildEventPrompt,
  buildEventResolved,
  buildEventError,
} from '../../src/events/v2/protocol.js';
import {
  parseEventEnvelope,
  parseEventResponseCommand,
} from '../../src/events/v2/schema.js';

describe('events v2 protocol schemas', () => {
  it('builds and validates event_prompt envelopes', () => {
    const envelope = buildEventPrompt({
      eventId: 'dilemma_found_wallet',
      instanceId: 'evt-inst-1',
      prompt: 'You found a wallet. What do you do?',
      choices: [
        { choiceId: 'return_wallet', text: 'Return it to the owner' },
        { choiceId: 'keep_cash', text: 'Keep the cash' },
      ],
      metadata: {
        category: 'dilemma',
      },
    });

    const parsed = parseEventEnvelope(envelope);

    expect(parsed.type).toBe('event_prompt');
    expect(parsed.eventId).toBe('dilemma_found_wallet');
    expect(parsed.choices).toHaveLength(2);
  });

  it('builds and validates event_resolved envelopes', () => {
    const envelope = buildEventResolved({
      eventId: 'dilemma_found_wallet',
      instanceId: 'evt-inst-1',
      resolutionText: 'You returned the wallet and felt proud.',
      effects: {
        stats: {
          happiness: 10,
        },
      },
    });

    const parsed = parseEventEnvelope(envelope);

    expect(parsed.type).toBe('event_resolved');
    expect(parsed.resolutionText).toContain('returned the wallet');
  });

  it('preserves named affinity changes in event_resolved envelopes', () => {
    const envelope = buildEventResolved({
      eventId: 'family_call',
      instanceId: 'evt-inst-2',
      resolutionText: 'You and Mom had a great talk.',
      effects: {
        relationships: [{ personId: 'mom-1', affinityDelta: 5 }],
      },
      resolvedRelationships: [{ personId: 'mom-1', name: 'Mom', affinityDelta: 5 }],
    });

    const parsed = parseEventEnvelope(envelope);

    expect(parsed.type).toBe('event_resolved');
    if (parsed.type === 'event_resolved') {
      expect(parsed.resolvedRelationships).toEqual([
        { personId: 'mom-1', name: 'Mom', affinityDelta: 5 },
      ]);
    }
  });

  it('builds and validates event_error envelopes', () => {
    const envelope = buildEventError({
      code: 'INVALID_CHOICE',
      message: 'That choice is no longer available.',
      eventId: 'dilemma_found_wallet',
      instanceId: 'evt-inst-1',
    });

    const parsed = parseEventEnvelope(envelope);

    expect(parsed.type).toBe('event_error');
    expect(parsed.code).toBe('INVALID_CHOICE');
  });

  it('parses eventResponse command payloads from websocket', () => {
    const parsed = parseEventResponseCommand({
      type: 'eventResponse',
      message: {
        eventId: 'evt-inst-1',
        choiceId: 'return_wallet',
      },
    });

    expect(parsed.type).toBe('eventResponse');
    expect(parsed.message.eventId).toBe('evt-inst-1');
    expect(parsed.message.choiceId).toBe('return_wallet');
  });

  it('rejects malformed eventResponse payloads', () => {
    expect(() =>
      parseEventResponseCommand({
        type: 'eventResponse',
        message: {
          eventId: 'evt-inst-1',
          // choiceId missing on purpose
        },
      })
    ).toThrow();
  });
});
