import fs from 'node:fs';
import path from 'node:path';
import { describe, expect, it } from 'vitest';
import { COMMAND_REGISTRY } from '../../src/handlers/index.js';
import {
  REGISTRY_COMMAND_NAMES,
  WEBSOCKET_COMMANDS,
} from '../../src/contracts/websocket-commands.js';

const fixtures = JSON.parse(
  fs.readFileSync(path.join(__dirname, 'fixtures', 'commands.json'), 'utf8')
) as Array<{ command: string }>;

describe('websocket command manifest', () => {
  it('matches COMMAND_REGISTRY keys exactly (excluding init)', () => {
    const registryKeys = Object.keys(COMMAND_REGISTRY).sort();
    const manifestKeys = REGISTRY_COMMAND_NAMES.sort();

    expect(manifestKeys).toEqual(registryKeys);
  });

  it('declares every registry command as client-to-server', () => {
    for (const name of REGISTRY_COMMAND_NAMES) {
      expect(WEBSOCKET_COMMANDS[name]?.direction).toBe('client-to-server');
    }
  });

  it('requires at least one payload variant per command', () => {
    for (const [name, contract] of Object.entries(WEBSOCKET_COMMANDS)) {
      if (contract.direction === 'client-to-server') {
        expect(contract.payloads.length, `${name} has no payload variants`).toBeGreaterThan(0);
      }
    }
  });

  it('every registry command has at least one golden fixture', () => {
    const fixtureCommands = new Set(fixtures.map((fixture) => fixture.command));
    const missing = REGISTRY_COMMAND_NAMES.filter((name) => !fixtureCommands.has(name));
    expect(missing).toEqual([]);
  });

  it('marks dev-only debug commands', () => {
    expect(WEBSOCKET_COMMANDS.debugSetup.flags).toContain('dev-only');
    expect(WEBSOCKET_COMMANDS.debugGrant.flags).toContain('dev-only');
  });

  it('documents quitHabit legacy string and object variants', () => {
    const contract = WEBSOCKET_COMMANDS.quitHabit;
    expect(contract.idKeys).toEqual(['habitId', 'habit']);
    expect(contract.payloads.some((p) => p.kind === 'string')).toBe(true);
    expect(contract.payloads.some((p) => p.kind === 'object')).toBe(true);
    expect(contract.responses?.some((r) => r.type === 'habitQuitting')).toBe(true);
  });
});

describe('command registry regressions', () => {
  it('registers relationshipEventResponse and dateMiniGameResponse commands', () => {
    expect(COMMAND_REGISTRY.relationshipEventResponse).toBeTypeOf('function');
    expect(COMMAND_REGISTRY.dateMiniGameResponse).toBeTypeOf('function');
  });

  it('registers iOS onboarding commands explicitly', () => {
    expect(COMMAND_REGISTRY.tutorialStepComplete).toBeTypeOf('function');
    expect(COMMAND_REGISTRY.completeOnboarding).toBeTypeOf('function');
    expect(COMMAND_REGISTRY.tooltipSeen).toBeTypeOf('function');
    expect(COMMAND_REGISTRY.debugSetup).toBeTypeOf('function');
    expect(COMMAND_REGISTRY.debugGrant).toBeTypeOf('function');
  });
});
