import { describe, expect, it, beforeAll, afterAll, vi } from 'vitest';
import { createServiceApp, type FastifyApp } from '@bytelyst/fastify-core';

vi.mock('../../lib/product-config.js', () => ({
  PRODUCT_ID: 'clawcowork',
  productConfig: { productId: 'clawcowork', displayName: 'Claw Cowork', backendPort: 4009 },
}));
vi.mock('../../lib/request-context.js', () => ({
  getUserId: () => 'demo-user',
  getRequestProductId: () => 'clawcowork',
}));
vi.mock('../../lib/ipc-bridge.js', () => ({
  getIpcBridge: () => ({ isRunning: false }),
}));

import { taskRoutes } from './routes.js';

let app: FastifyApp;

beforeAll(async () => {
  app = await createServiceApp({
    name: 'cowork-test',
    version: '0.0.1',
    logger: false,
  });
  await app.register(taskRoutes);
});

afterAll(async () => {
  await app.close();
});

describe('task routes', () => {
  it('POST /api/tasks — submits a task and returns 201', async () => {
    const res = await app.inject({
      method: 'POST',
      url: '/api/tasks',
      payload: {
        goal: 'List all files and create a summary',
        folder: '/tmp/test-folder',
      },
    });

    expect(res.statusCode).toBe(201);
    const body = JSON.parse(res.payload);
    expect(body.id).toMatch(/^task_/);
    expect(body.productId).toBe('clawcowork');
    expect(body.goal).toBe('List all files and create a summary');
    expect(body.folder).toBe('/tmp/test-folder');
    expect(body.status).toBe('pending');
    expect(body.model).toBe('claude-sonnet-4-20250514');
  });

  it('POST /api/tasks — rejects empty goal', async () => {
    const res = await app.inject({
      method: 'POST',
      url: '/api/tasks',
      payload: { goal: '', folder: '/tmp' },
    });

    expect(res.statusCode).toBe(400);
  });

  it('GET /api/tasks — lists submitted tasks', async () => {
    const res = await app.inject({ method: 'GET', url: '/api/tasks' });

    expect(res.statusCode).toBe(200);
    const body = JSON.parse(res.payload);
    expect(body.tasks).toBeInstanceOf(Array);
    expect(body.tasks.length).toBeGreaterThanOrEqual(1);
  });

  it('GET /api/tasks/:id — returns a specific task', async () => {
    // Submit first
    const submitRes = await app.inject({
      method: 'POST',
      url: '/api/tasks',
      payload: { goal: 'Get task test', folder: '/tmp' },
    });
    const { id } = JSON.parse(submitRes.payload);

    const res = await app.inject({ method: 'GET', url: `/api/tasks/${id}` });
    expect(res.statusCode).toBe(200);
    expect(JSON.parse(res.payload).id).toBe(id);
  });

  it('GET /api/tasks/:id — returns 404 for unknown task', async () => {
    const res = await app.inject({ method: 'GET', url: '/api/tasks/nonexistent' });
    expect(res.statusCode).toBe(404);
  });

  it('POST /api/tasks/:id/cancel — cancels a pending task', async () => {
    const submitRes = await app.inject({
      method: 'POST',
      url: '/api/tasks',
      payload: { goal: 'Cancel me', folder: '/tmp' },
    });
    const { id } = JSON.parse(submitRes.payload);

    const cancelRes = await app.inject({
      method: 'POST',
      url: `/api/tasks/${id}/cancel`,
    });
    expect(cancelRes.statusCode).toBe(200);
    expect(JSON.parse(cancelRes.payload).status).toBe('cancelled');
  });

  it('POST /api/tasks/:id/cancel — rejects cancel on already cancelled task', async () => {
    const submitRes = await app.inject({
      method: 'POST',
      url: '/api/tasks',
      payload: { goal: 'Double cancel', folder: '/tmp' },
    });
    const { id } = JSON.parse(submitRes.payload);

    await app.inject({ method: 'POST', url: `/api/tasks/${id}/cancel` });
    const res = await app.inject({ method: 'POST', url: `/api/tasks/${id}/cancel` });
    expect(res.statusCode).toBe(400);
  });
});
