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

import {
  buildTelemetryEvent,
  telemetryEventCatalog,
  telemetryEventSchemas,
  type TelemetryCommonEnvelope,
} from '../../src/telemetry/events.js';

const envelope: TelemetryCommonEnvelope = {
  cliVersion: '0.4.1',
  nodeVersion: 'v22.0.0',
  osPlatform: 'darwin',
  osRelease: '25.0.0',
  arch: 'arm64',
  runtime: 'node',
  isCi: false,
};

describe('telemetry event schemas', () => {
  it('catalogs all v1 telemetry events', () => {
    expect(telemetryEventCatalog.map((event) => event.name)).toEqual([
      'install_first_run',
      'command',
      'setup_step',
      'connection_added',
      'connection_test',
      'project_stack_snapshot',
      'ingest_completed',
      'scan_completed',
      'sl_validate_completed',
      'sl_query_completed',
      'sql_completed',
      'wiki_query_completed',
      'mcp_request_completed',
      'daemon_started',
      'daemon_stopped',
      'sl_plan_completed',
      'sql_gen_completed',
    ]);
  });

  it('builds strict daemon telemetry events', () => {
    const daemonEnvelope = {
      ...envelope,
      runtime: 'daemon-py' as const,
      nodeVersion: '3.13.0',
    };

    expect(
      buildTelemetryEvent('sl_plan_completed', daemonEnvelope, {
        outcome: 'ok',
        stage: 'transpile',
        durationMs: 25,
        sourceCount: 2,
        joinCount: 1,
      }),
    ).toMatchObject({
      name: 'sl_plan_completed',
      properties: {
        runtime: 'daemon-py',
        outcome: 'ok',
        stage: 'transpile',
        sourceCount: 2,
        joinCount: 1,
      },
    });

    expect(() =>
      telemetryEventSchemas.sql_gen_completed.parse({
        ...daemonEnvelope,
        outcome: 'ok',
        dialect: 'postgres',
        durationMs: 4,
        sql: 'select * from private_table',
      }),
    ).toThrow();
  });

  it('builds a strict install_first_run event', () => {
    expect(buildTelemetryEvent('install_first_run', envelope, {})).toEqual({
      name: 'install_first_run',
      properties: envelope,
    });
  });

  it('builds a strict command event with project grouping fields', () => {
    expect(
      buildTelemetryEvent('command', envelope, {
        commandPath: ['ktx', 'status'],
        durationMs: 12,
        outcome: 'ok',
        flagsPresent: { json: true },
        hasProject: true,
        projectGroupAttached: true,
      }),
    ).toEqual({
      name: 'command',
      properties: {
        ...envelope,
        commandPath: ['ktx', 'status'],
        durationMs: 12,
        outcome: 'ok',
        flagsPresent: { json: true },
        hasProject: true,
        projectGroupAttached: true,
      },
    });
  });

  it('rejects unmodeled event properties', () => {
    expect(() =>
      telemetryEventSchemas.command.parse({
        ...envelope,
        commandPath: ['ktx', 'status'],
        durationMs: 12,
        outcome: 'ok',
        flagsPresent: {},
        hasProject: true,
        projectGroupAttached: true,
        tableName: 'private_table',
      }),
    ).toThrow();
  });

  it('builds strict Phase 2 events without private names or text', () => {
    expect(
      buildTelemetryEvent('connection_test', envelope, {
        driver: 'postgres',
        isDemoConnection: false,
        outcome: 'ok',
        durationMs: 34,
        serverVersion: '16',
      }),
    ).toMatchObject({
      name: 'connection_test',
      properties: {
        driver: 'postgres',
        isDemoConnection: false,
        outcome: 'ok',
        durationMs: 34,
        serverVersion: '16',
      },
    });

    expect(() =>
      telemetryEventSchemas.sql_completed.parse({
        ...envelope,
        driver: 'postgres',
        isDemoConnection: false,
        queryVerb: 'select',
        referencedTableCount: 1,
        durationMs: 10,
        outcome: 'ok',
        sql: 'select * from private_table',
      }),
    ).toThrow();
  });

  it('rejects raw private field names that are not in the telemetry schemas', () => {
    expect(JSON.stringify(telemetryEventSchemas)).not.toContain('tableName');
    expect(Object.keys(telemetryEventSchemas.sql_completed.shape)).not.toContain('sql');
    expect(JSON.stringify(telemetryEventSchemas)).not.toContain('path');
  });
});
