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

const runRepoMock = {
  listRuns: vi.fn(),
};

const sessionRepoMock = {
  listAllUserSessions: vi.fn(),
};

vi.mock('../runs/repository.js', () => runRepoMock);
vi.mock('../sessions/repository.js', () => sessionRepoMock);

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

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

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

  it('GET /agent-runtime/sessions projects session docs into the shared runtime shape', async () => {
    sessionRepoMock.listAllUserSessions.mockResolvedValue([
      {
        id: 'sess_1',
        productId: 'lysnrai',
        userId: 'user_1',
        platform: 'web',
        ipAddress: '127.0.0.1',
        userAgent: 'test',
        lastActiveAt: '2026-04-04T18:00:00.000Z',
        createdAt: '2026-04-04T17:00:00.000Z',
        expiresAt: '2099-04-04T17:00:00.000Z',
      },
    ]);
    const app = await buildApp({ sub: 'user_1', productId: 'lysnrai' });

    const res = await app.inject({
      method: 'GET',
      url: '/api/agent-runtime/sessions',
    });

    expect(res.statusCode).toBe(200);
    const body = JSON.parse(res.body);
    expect(body.sessions[0]).toMatchObject({
      sessionId: 'sess_1',
      productId: 'lysnrai',
      userId: 'user_1',
      status: 'active',
    });
    expect(body.sessions[0].dispatchContext.originSurface).toBe('web');
  });

  it('GET /agent-runtime/runs projects run docs into the shared runtime shape', async () => {
    runRepoMock.listRuns.mockResolvedValue([
      {
        id: 'run_1',
        productId: 'lysnrai',
        kind: 'agent',
        name: 'runtime-check',
        source: 'dispatch',
        status: 'succeeded',
        createdAt: '2026-04-04T18:00:00.000Z',
        updatedAt: '2026-04-04T18:10:00.000Z',
        completedAt: '2026-04-04T18:10:00.000Z',
        metadata: {
          sessionId: 'sess_1',
          correlationId: 'corr_1',
        },
      },
    ]);
    const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });

    const res = await app.inject({
      method: 'GET',
      url: '/api/agent-runtime/runs?limit=10',
    });

    expect(res.statusCode).toBe(200);
    const body = JSON.parse(res.body);
    expect(body.runs[0]).toMatchObject({
      runId: 'run_1',
      sessionId: 'sess_1',
      productId: 'lysnrai',
      status: 'completed',
      correlationId: 'corr_1',
    });
  });

  it('GET /agent-runtime/runs preserves queued runs as queued', async () => {
    runRepoMock.listRuns.mockResolvedValue([
      {
        id: 'run_queued',
        productId: 'lysnrai',
        kind: 'agent',
        name: 'queued-run',
        source: 'dispatch',
        status: 'queued',
        createdAt: '2026-04-04T18:00:00.000Z',
        updatedAt: '2026-04-04T18:10:00.000Z',
        metadata: {
          sessionId: 'sess_queued',
        },
      },
    ]);
    const app = await buildApp({ sub: 'admin_1', productId: 'lysnrai', role: 'admin' });

    const res = await app.inject({
      method: 'GET',
      url: '/api/agent-runtime/runs?limit=10',
    });

    expect(res.statusCode).toBe(200);
    const body = JSON.parse(res.body);
    expect(body.runs[0]).toMatchObject({
      runId: 'run_queued',
      sessionId: 'sess_queued',
      status: 'queued',
    });
  });

  it('POST /agent-runtime/dispatch/validate validates the shared dispatch contract', async () => {
    const app = await buildApp({ sub: 'user_1', productId: 'lysnrai' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/agent-runtime/dispatch/validate',
      payload: {
        dispatchId: 'dispatch_1',
        targetProductId: 'lysnrai',
        targetExecutor: 'generic-agent',
        userId: 'user_1',
        title: 'Review latest transcript',
        intent: 'Summarize and prepare a memory candidate.',
        artifactRefs: ['art_1'],
        memoryRefs: [],
        dispatchContext: {
          originSurface: 'web',
          originProductId: 'lysnrai',
          dispatchMode: 'interactive',
          initiatedAt: '2026-04-04T18:00:00.000Z',
        },
      },
    });

    expect(res.statusCode).toBe(200);
    expect(JSON.parse(res.body).valid).toBe(true);
  });
});
