import { Database } from 'bun:sqlite';
import fs from 'fs';
import path from 'path';

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

import { applyBaseSchema } from './base-schema.js';
import { initializeDatabaseSchema } from './bootstrap.js';
import { applyLegacySchemaMigrations } from './schema.js';

function getAppliedSchemaMigrations(
  database: Database,
): Array<{ version: number; name: string }> {
  return database
    .prepare(
      `SELECT version, name
         FROM schema_migrations
        ORDER BY version ASC`,
    )
    .all() as Array<{ version: number; name: string }>;
}

function getExpectedSchemaMigrations(): Array<{
  version: number;
  name: string;
}> {
  return [
    { version: 1, name: 'legacy_schema_bundle' },
    { version: 2, name: 'scheduled_task_columns' },
    { version: 3, name: 'room_registration_canonical_columns' },
    { version: 4, name: 'message_seq_and_work_item_indexes' },
    { version: 5, name: 'sessions_composite_key' },
    { version: 6, name: 'chat_channel_metadata' },
    { version: 7, name: 'runtime_service_metadata' },
    { version: 8, name: 'paired_task_schema_cleanup' },
    { version: 9, name: 'paired_workspace_project_schema_cleanup' },
    { version: 10, name: 'paired_turn_provenance_upgrade' },
    { version: 11, name: 'owner_failure_count' },
  ];
}

describe('initializeDatabaseSchema', () => {
  const tempDirs: string[] = [];

  afterEach(() => {
    for (const tempDir of tempDirs.splice(0)) {
      fs.rmSync(tempDir, { recursive: true, force: true });
    }
  });

  it('records the legacy schema bundle as version 1 on a fresh database', () => {
    const database = new Database(':memory:');

    try {
      initializeDatabaseSchema(database);

      expect(getAppliedSchemaMigrations(database)).toEqual(
        getExpectedSchemaMigrations(),
      );
    } finally {
      database.close();
    }
  });

  it('does not duplicate schema migration rows on repeated initialization', () => {
    const database = new Database(':memory:');

    try {
      initializeDatabaseSchema(database);
      initializeDatabaseSchema(database);

      expect(getAppliedSchemaMigrations(database)).toEqual(
        getExpectedSchemaMigrations(),
      );
    } finally {
      database.close();
    }
  });

  it('backfills schema migration tracking for an existing pre-versioned database', () => {
    const tempDir = fs.mkdtempSync(
      path.join('/tmp', 'ejclaw-schema-migrations-'),
    );
    tempDirs.push(tempDir);
    const dbPath = path.join(tempDir, 'messages.db');
    const legacyDb = new Database(dbPath);

    try {
      applyBaseSchema(legacyDb);
      applyLegacySchemaMigrations(legacyDb, {
        assistantName: 'Andy',
      });
    } finally {
      legacyDb.close();
    }

    const reopened = new Database(dbPath);

    try {
      initializeDatabaseSchema(reopened);

      expect(getAppliedSchemaMigrations(reopened)).toEqual(
        getExpectedSchemaMigrations(),
      );
    } finally {
      reopened.close();
    }
  });
});
