import { strict as assert } from 'node:assert';
import { describe, it } from 'node:test';
import type { Database } from '@pig/db';
import { facts } from '@pig/db';
import type { Principal } from '../src/lib/auth';
import { executeMutation, MutationError } from '../src/lib/mutation';
import { factDecisionDefinition } from '../src/routes/facts';

const reviewer: Principal = {
  userId: '00000000-0000-0000-0000-000000000001',
  email: 'research@example.com',
  name: 'Research reviewer',
  isPlatformAdmin: false,
  teams: [{ team: 'research', role: 'admin' }],
  via: 'jwt',
  scopes: ['read', 'write'],
};

const proposedFact = {
  id: '10000000-0000-0000-0000-000000000001',
  accountId: '20000000-0000-0000-0000-000000000001',
  contactId: null,
  field: 'supplierType',
  value: 'neocloud',
  score: '0.780',
  band: 'probable',
  status: 'proposed',
  evidence: { excerpt: 'Operates dedicated GPU cloud regions.' },
  sourceUrl: 'https://example.com/infrastructure',
  method: 'web_search',
  agentRunId: null,
  decidedByUserId: null,
  decidedAt: null,
  observedAt: new Date('2026-08-12T10:00:00Z'),
  supersededAt: null,
  createdAt: new Date('2026-08-12T10:00:00Z'),
} as const;

function fakeDatabase(initial: Record<string, unknown>) {
  let stored = { ...initial };
  const updates: { table: unknown; values: Record<string, unknown> }[] = [];
  const activities: Record<string, unknown>[] = [];

  const tx = {
    select: () => ({
      from: () => ({
        where: () => ({ limit: async () => [stored] }),
      }),
    }),
    update: (table: unknown) => ({
      set: (values: Record<string, unknown>) => ({
        where: () => ({
          returning: async () => {
            updates.push({ table, values });
            stored = { ...stored, ...values };
            return [stored];
          },
        }),
      }),
    }),
    insert: () => ({
      values: async (row: Record<string, unknown>) => {
        activities.push(row);
      },
    }),
  };

  const db = {
    transaction: async (work: (transaction: unknown) => Promise<unknown>) => work(tx),
  } as unknown as Database;

  return { db, updates, activities };
}

describe('fact review decisions', () => {
  it('approves evidence without applying an arbitrary field to the CRM record', async () => {
    const state = fakeDatabase(proposedFact);

    const result = await executeMutation(
      state.db,
      reviewer,
      async () => ({ status: 'approved' }),
      factDecisionDefinition,
      { id: proposedFact.id },
    );

    assert.equal(result.fact.status, 'approved');
    assert.equal(result.recordUpdated, false);
    assert.equal(state.updates.length, 1);
    assert.equal(state.updates[0]?.table, facts);
    assert.deepEqual(state.updates[0]?.values, {
      status: 'approved',
      decidedByUserId: reviewer.userId,
      decidedAt: state.updates[0]?.values.decidedAt,
    });
    assert.ok(state.updates[0]?.values.decidedAt instanceof Date);
    assert.deepEqual(state.activities[0]?.meta, {
      factId: proposedFact.id,
      decision: 'approved',
      field: proposedFact.field,
      recordUpdated: false,
    });
  });

  it('refuses to approve an unsupported claim', async () => {
    const state = fakeDatabase({
      ...proposedFact,
      evidence: null,
      sourceUrl: null,
    });

    await assert.rejects(
      executeMutation(
        state.db,
        reviewer,
        async () => ({ status: 'approved' }),
        factDecisionDefinition,
        { id: proposedFact.id },
      ),
      (error: unknown) =>
        error instanceof MutationError && error.code === 'missing_evidence',
    );
    assert.deepEqual(state.updates, []);
    assert.deepEqual(state.activities, []);
  });

  it('allows an unsupported proposal to be dismissed without manufacturing evidence', async () => {
    const state = fakeDatabase({
      ...proposedFact,
      evidence: null,
      sourceUrl: null,
    });

    const result = await executeMutation(
      state.db,
      reviewer,
      async () => ({ status: 'dismissed' }),
      factDecisionDefinition,
      { id: proposedFact.id },
    );

    assert.equal(result.fact.status, 'dismissed');
    assert.equal(result.recordUpdated, false);
    assert.equal(state.updates.length, 1);
    assert.equal(state.updates[0]?.table, facts);
  });
});
