/**
 * Tests for agent report CRUD query helpers.
 *
 * Each test initializes an in-memory PGlite instance, creates the schema,
 * exercises the query function, and tears down the database.
 */

import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'bun:test';
import { setupTestDb, cleanTestDb, teardownTestDb } from '../../helpers/db';
import { registerAgent } from '@myco/db/queries/agents.js';
import { insertRun } from '@myco/db/queries/runs.js';
import {
  insertReport,
  listReports,
  listReportsByAgent,
} from '@myco/db/queries/reports.js';
import type { ReportInsert } from '@myco/db/queries/reports.js';
import { ALL_PROJECTS_SCOPE } from '@myco/grove/ids.js';

/** Epoch seconds helper. */
const epochNow = () => Math.floor(Date.now() / 1000);

/** Shared agent and run IDs used across tests. */
const TEST_AGENT_ID = 'agent-reports-test';
const TEST_RUN_ID = 'run-reports-test';

/** Factory for minimal valid report data. */
function makeReport(overrides: Partial<ReportInsert> = {}): ReportInsert {
  return {
    run_id: TEST_RUN_ID,
    agent_id: TEST_AGENT_ID,
    action: 'write_spore',
    summary: 'Created a new spore',
    created_at: epochNow(),
    ...overrides,
  };
}

describe('report query helpers', () => {
  beforeAll(() => { setupTestDb(); });
  afterAll(() => { teardownTestDb(); });
  beforeEach(async () => {
    cleanTestDb();
    // Insert FK targets
    registerAgent({
      id: TEST_AGENT_ID,
      name: 'Test Agent',
      created_at: epochNow(),
    });
    insertRun({
      id: TEST_RUN_ID,
      agent_id: TEST_AGENT_ID,
      started_at: epochNow(),
    });
  });

  // ---------------------------------------------------------------------------
  // insertReport
  // ---------------------------------------------------------------------------

  describe('insertReport', () => {
    it('inserts a report and returns it with auto-generated id', async () => {
      const data = makeReport();
      const row = insertReport(data);

      expect(typeof row.id).toBe('number');
      expect(row.run_id).toBe(TEST_RUN_ID);
      expect(row.agent_id).toBe(TEST_AGENT_ID);
      expect(row.action).toBe('write_spore');
      expect(row.summary).toBe('Created a new spore');
      expect(row.details).toBeNull();
      expect(row.created_at).toBe(data.created_at);
    });

    it('stores details as JSON string', async () => {
      const details = JSON.stringify({ spore_id: 'spore-abc', type: 'gotcha' });
      const data = makeReport({ details });
      const row = insertReport(data);

      expect(row.details).toBe(details);
    });
  });

  // ---------------------------------------------------------------------------
  // listReports
  // ---------------------------------------------------------------------------

  describe('listReports', () => {
    it('returns reports for a run ordered by created_at ASC', async () => {
      const now = epochNow();
      insertReport(makeReport({ summary: 'First', created_at: now - 20 }));
      insertReport(makeReport({ summary: 'Second', created_at: now - 10 }));
      insertReport(makeReport({ summary: 'Third', created_at: now }));

      const rows = listReports(TEST_RUN_ID, { scope: ALL_PROJECTS_SCOPE });
      expect(rows).toHaveLength(3);
      expect(rows[0].summary).toBe('First');
      expect(rows[1].summary).toBe('Second');
      expect(rows[2].summary).toBe('Third');
    });

    it('returns empty array for run with no reports', async () => {
      const rows = listReports('no-such-run', { scope: ALL_PROJECTS_SCOPE });
      expect(rows).toEqual([]);
    });
  });

  // ---------------------------------------------------------------------------
  // listReportsByAgent
  // ---------------------------------------------------------------------------

  describe('listReportsByAgent', () => {
    it('returns reports by agent ordered by created_at DESC', async () => {
      const now = epochNow();
      insertReport(makeReport({ summary: 'Old', created_at: now - 100 }));
      insertReport(makeReport({ summary: 'New', created_at: now }));

      const rows = listReportsByAgent(TEST_AGENT_ID, { scope: ALL_PROJECTS_SCOPE });
      expect(rows).toHaveLength(2);
      expect(rows[0].summary).toBe('New');
      expect(rows[1].summary).toBe('Old');
    });

    it('respects limit', async () => {
      const now = epochNow();
      insertReport(makeReport({ created_at: now - 2 }));
      insertReport(makeReport({ created_at: now - 1 }));
      insertReport(makeReport({ created_at: now }));

      const rows = listReportsByAgent(TEST_AGENT_ID, { limit: 2, scope: ALL_PROJECTS_SCOPE });
      expect(rows).toHaveLength(2);
    });

    it('returns empty array for agent with no reports', async () => {
      const rows = listReportsByAgent('no-such-agent', { scope: ALL_PROJECTS_SCOPE });
      expect(rows).toEqual([]);
    });
  });
});
