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

import { openInitializedInMemoryDatabase } from './database-lifecycle.js';
import {
  getStoredRoomRowsFromDatabase,
  getStoredRoomSettingsRowFromDatabase,
  insertStoredRoomSettings,
} from './room-registration.js';

// Regression guard for the cgv-macro incident: a room_settings row that carried
// an invalid mode_source ('room') was silently dropped from every binding
// lookup, so the router ignored the channel, it vanished from the status list,
// and re-registration wedged on the UNIQUE(chat_jid) constraint. The loader must
// keep such a room routable by coercing the bad source to a valid one.
describe('getStoredRoomSettingsRowFromDatabase mode_source resilience', () => {
  const jid = 'dc:invalid-source-room';
  const snapshot = {
    name: 'cgv-macro',
    folder: 'cgv-macro',
    triggerPattern: '',
    requiresTrigger: false,
    isMain: false,
    ownerAgentType: 'claude-code' as const,
    workDir: null,
  };

  function seedWithSource(source: string) {
    const db = openInitializedInMemoryDatabase();
    insertStoredRoomSettings(db, jid, 'single', 'explicit', snapshot);
    db.prepare(
      'UPDATE room_settings SET mode_source = ? WHERE chat_jid = ?',
    ).run(source, jid);
    return db;
  }

  it('coerces an unrecognized mode_source to explicit instead of dropping the room', () => {
    const db = seedWithSource('room');

    const stored = getStoredRoomSettingsRowFromDatabase(db, jid);
    expect(stored).toBeDefined();
    expect(stored?.roomMode).toBe('single');
    expect(stored?.modeSource).toBe('explicit');
    expect(stored?.folder).toBe('cgv-macro');

    // And it stays visible in the full-room listing that feeds getAllRoomBindings.
    const listed = getStoredRoomRowsFromDatabase(db).map((r) => r.chatJid);
    expect(listed).toContain(jid);
  });

  it('room_mode is guarded by a schema CHECK, but mode_source is not — hence the loader coercion', () => {
    const db = openInitializedInMemoryDatabase();
    insertStoredRoomSettings(db, jid, 'single', 'explicit', snapshot);

    // room_mode cannot be corrupted at all: the column CHECK rejects the write.
    expect(() =>
      db
        .prepare('UPDATE room_settings SET room_mode = ? WHERE chat_jid = ?')
        .run('bogus', jid),
    ).toThrow(/CHECK constraint/);

    // mode_source has no such CHECK, so a bad value persists — which is exactly
    // the corruption the loader now tolerates instead of dropping the room.
    db.prepare(
      'UPDATE room_settings SET mode_source = ? WHERE chat_jid = ?',
    ).run('room', jid);
    expect(getStoredRoomSettingsRowFromDatabase(db, jid)?.roomMode).toBe(
      'single',
    );
  });

  it('preserves a valid mode_source unchanged', () => {
    const db = openInitializedInMemoryDatabase();
    insertStoredRoomSettings(db, jid, 'tribunal', 'inferred', snapshot);

    expect(getStoredRoomSettingsRowFromDatabase(db, jid)?.modeSource).toBe(
      'inferred',
    );
  });
});
