import { test } from 'node:test';
import { strict as assert } from 'node:assert';

import { generate, type SchemaSnapshot } from './codegen.js';

test('generate emits dataModel.d.ts with Doc<T> for each table', () => {
  const snapshot: SchemaSnapshot = {
    version: 1,
    tables: {
      notes: {
        columns: {
          id: { sqlType: 'text', nullable: false, primaryKey: true, unique: false },
          body: { sqlType: 'text', nullable: false, primaryKey: false, unique: false },
          archived: { sqlType: 'boolean', nullable: true, primaryKey: false, unique: false },
        },
        indexes: [],
      },
    },
  };
  const out = generate(snapshot, []);
  const dm = out.get('briven/_generated/dataModel.d.ts');
  assert.ok(dm, 'dataModel.d.ts must be emitted');
  assert.match(dm, /export interface Notes \{/);
  assert.match(dm, /id: string;/);
  assert.match(dm, /body: string;/);
  assert.match(dm, /archived: boolean \| null;/);
  assert.match(dm, /export type Doc<T extends keyof Tables> = Tables\[T\];/);
});

test('generate emits api.ts with imports + typed api object', () => {
  const snapshot: SchemaSnapshot = { version: 1, tables: {} };
  const out = generate(snapshot, ['listNotes.ts', 'createNote.ts']);
  const api = out.get('briven/_generated/api.ts');
  assert.ok(api, 'api.ts must be emitted');
  assert.match(api, /import listNotes from '\.\.\/functions\/listNotes\.js';/);
  assert.match(api, /import createNote from '\.\.\/functions\/createNote\.js';/);
  assert.match(api, /export const api = \{/);
  assert.match(api, / {2}listNotes,/);
  assert.match(api, / {2}createNote,/);
});

test('generate maps every supported sql type to TS', () => {
  const snapshot: SchemaSnapshot = {
    version: 1,
    tables: {
      t: {
        columns: {
          a: { sqlType: 'text', nullable: false, primaryKey: true, unique: false },
          b: { sqlType: 'integer', nullable: false, primaryKey: false, unique: false },
          c: { sqlType: 'bigint', nullable: false, primaryKey: false, unique: false },
          d: { sqlType: 'boolean', nullable: false, primaryKey: false, unique: false },
          e: { sqlType: 'timestamptz', nullable: false, primaryKey: false, unique: false },
          f: { sqlType: 'jsonb', nullable: false, primaryKey: false, unique: false },
          g: { sqlType: 'uuid', nullable: false, primaryKey: false, unique: false },
          h: { sqlType: 'varchar(255)', nullable: false, primaryKey: false, unique: false },
          i: { sqlType: 'vector(1536)', nullable: false, primaryKey: false, unique: false },
        },
        indexes: [],
      },
    },
  };
  const dm = generate(snapshot, []).get('briven/_generated/dataModel.d.ts')!;
  assert.match(dm, /a: string;/);
  assert.match(dm, /b: number;/);
  assert.match(dm, /c: bigint;/);
  assert.match(dm, /d: boolean;/);
  assert.match(dm, /e: string;/);
  assert.match(dm, /f: unknown;/);
  assert.match(dm, /g: string;/);
  assert.match(dm, /h: string;/);
  assert.match(dm, /i: number\[\];/);
});

test('generate always includes a README in _generated', () => {
  const out = generate({ version: 1, tables: {} }, []);
  const readme = out.get('briven/_generated/README.md');
  assert.ok(readme);
  assert.match(readme, /Generated by briven cli\. Do not edit by hand\./);
});

test('generate emits empty api object when no functions', () => {
  const out = generate({ version: 1, tables: {} }, []);
  const api = out.get('briven/_generated/api.ts');
  assert.ok(api);
  assert.match(api, /export const api = \{\} as const;/);
});
