import Fastify from 'fastify';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const repoMock = {
  listRuns: vi.fn(),
  getRun: vi.fn(),
  listRunSteps: vi.fn(),
  updateRun: vi.fn(),
  updateRunStep: vi.fn(),
};

const trackerMock = {
  startRun: vi.fn(),
  completeRun: vi.fn(),
  failRun: vi.fn(),
  startRunStep: vi.fn(),
  completeRunStep: vi.fn(),
  failRunStep: vi.fn(),
};

vi.mock('./repository.js', () => repoMock);
vi.mock('./tracker.js', () => trackerMock);

async function buildApp(payload?: { sub: string; productId: string; role?: string }) {
  const { runRoutes } = await import('./routes.js');
  const app = Fastify({ logger: false });
  if (payload) {
    app.addHook('onRequest', async req => {
      req.jwtPayload = payload;
    });
  }
  await app.register(runRoutes, { prefix: '/api' });
  return app;
}

describe('runRoutes', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('POST /runs creates a durable run for admin jwt callers', async () => {
    trackerMock.startRun.mockResolvedValue({ id: 'run_1', status: 'running' });
    const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/runs',
      payload: {
        id: 'run_1',
        kind: 'agent',
        name: 'incident-pipeline',
        source: 'mcp.a2a',
      },
    });

    expect(res.statusCode).toBe(200);
    expect(trackerMock.startRun).toHaveBeenCalledWith({
      id: 'run_1',
      kind: 'agent',
      name: 'incident-pipeline',
      source: 'mcp.a2a',
      productId: 'lysnrai',
      triggeredBy: 'admin_1',
    });
  });

  it('PATCH /runs/:id completes a run', async () => {
    trackerMock.completeRun.mockResolvedValue({ id: 'run_1', status: 'succeeded' });
    const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });

    const res = await app.inject({
      method: 'PATCH',
      url: '/api/runs/run_1',
      payload: {
        status: 'succeeded',
        output: { reportId: 'rep_1' },
      },
    });

    expect(res.statusCode).toBe(200);
    expect(trackerMock.completeRun).toHaveBeenCalledWith('run_1', 'lysnrai', {
      reportId: 'rep_1',
    });
  });
});
