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

// The module under test imports @mosaicstack/db at module scope; we replace only the
// pieces DatabaseModule uses (partial mock — the real module also exports the
// schema the storage adapter's import chain needs) so the test pins the #1392
// contract (refuse to start on an incomplete schema) without a live database.
vi.mock('@mosaicstack/db', async (importOriginal) => {
  const actual: object = await importOriginal();
  return {
    ...actual,
    createDb: vi.fn(),
    createPgliteDb: vi.fn(),
    getMigrationStatus: vi.fn(),
    runPgliteMigrations: vi.fn(),
  };
});

import { DatabaseModule } from './database.module.js';
import { getMigrationStatus } from '@mosaicstack/db';
import type { DbHandle } from '@mosaicstack/db';
import type { StorageAdapter } from '@mosaicstack/storage';
import type { MosaicConfig } from '@mosaicstack/config';

function makeModule(storageType: 'postgres' | 'pglite', tier: string) {
  const storageAdapter = {
    name: storageType,
    migrate: vi.fn(),
    close: vi.fn(),
  } as unknown as StorageAdapter;
  const handle = { close: vi.fn() } as unknown as DbHandle;
  const config = {
    tier,
    storage: { type: storageType, url: 'postgresql://x' },
  } as unknown as MosaicConfig;
  return {
    mod: new DatabaseModule(handle, storageAdapter, config),
    storageAdapter,
  };
}

describe('DatabaseModule.onModuleInit — #1392 schema verification', () => {
  it('refuses to start when the postgres schema is incomplete', async () => {
    const { mod, storageAdapter } = makeModule('postgres', 'standalone');
    vi.mocked(getMigrationStatus).mockResolvedValue({
      appliedCount: 15,
      expectedCount: 17,
      expectedLastTag: '0016_salty_morlocks',
      complete: false,
    });
    await expect(mod.onModuleInit()).rejects.toThrow('Database schema incomplete: 15/17');
    expect(storageAdapter.migrate).toHaveBeenCalled(); // migrations attempted first
  });

  it('starts normally when the schema is complete', async () => {
    const { mod } = makeModule('postgres', 'standalone');
    vi.mocked(getMigrationStatus).mockResolvedValue({
      appliedCount: 17,
      expectedCount: 17,
      expectedLastTag: '0016_salty_morlocks',
      complete: true,
    });
    await expect(mod.onModuleInit()).resolves.toBeUndefined();
  });

  it('does not verify postgres status for the local tier (PGlite migrates itself)', async () => {
    const { mod } = makeModule('pglite', 'local');
    vi.mocked(getMigrationStatus).mockClear();
    await expect(mod.onModuleInit()).resolves.toBeUndefined();
    expect(getMigrationStatus).not.toHaveBeenCalled();
  });
});
