/**
 * Boulder state — plan routes.
 *
 * GET   /api/plans?project_id=   — list plans for a project
 * GET   /api/plans/active?project_id= — list active (in-flight) plans
 * POST   /api/plans               — create a new plan
 * PATCH  /api/plans/:id           — update plan progress / status
 */
import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import type { Sql } from '../db.js';
import {
  createPlan,
  getPlan,
  listPlans,
  listActivePlans,
  updatePlan,
} from '../services/plan-store.js';

const CreatePlanBody = z.object({
  project_id: z.string().uuid(),
  title: z.string().min(1).max(500),
  description: z.string().max(10_000).optional(),
  flow_run_id: z.string().uuid().optional(),
  metadata: z.record(z.unknown()).optional(),
});

const ListPlansQuery = z.object({
  project_id: z.string().uuid(),
});

const UpdatePlanBody = z.object({
  title: z.string().min(1).max(500).optional(),
  description: z.string().max(10_000).nullable().optional(),
  status: z.enum(['active', 'completed', 'cancelled', 'failed']).optional(),
  progress_pct: z.number().int().min(0).max(100).optional(),
  items_total: z.number().int().min(0).optional(),
  items_completed: z.number().int().min(0).optional(),
  metadata: z.record(z.unknown()).nullable().optional(),
});

const PlanIdParam = z.string().uuid();

export function registerPlanRoutes(app: FastifyInstance, sql: Sql): void {
  // GET /api/plans?project_id= — all plans for a project
  app.get('/api/plans', async (req, reply) => {
    const parsed = ListPlansQuery.safeParse(req.query);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'invalid query', details: parsed.error.flatten() };
    }
    const plans = await listPlans(sql, parsed.data.project_id);
    return { plans };
  });

  // GET /api/plans/active?project_id= — active plans only
  app.get('/api/plans/active', async (req, reply) => {
    const parsed = ListPlansQuery.safeParse(req.query);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'invalid query', details: parsed.error.flatten() };
    }
    const plans = await listActivePlans(sql, parsed.data.project_id);
    return { plans };
  });

  // POST /api/plans — create a new plan
  app.post('/api/plans', async (req, reply) => {
    const parsed = CreatePlanBody.safeParse(req.body);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'invalid body', details: parsed.error.flatten() };
    }

    const { project_id, title, description, flow_run_id, metadata } = parsed.data;
    const plan = await createPlan(sql, {
      projectId: project_id,
      title,
      description,
      flowRunId: flow_run_id,
      metadata,
    });

    reply.code(201);
    return { plan };
  });

  app.get<{ Params: { id: string } }>('/api/plans/:id', async (req, reply) => {
    const parsedId = PlanIdParam.safeParse(req.params.id);
    if (!parsedId.success) {
      reply.code(400);
      return { error: 'invalid id' };
    }
    const plan = await getPlan(sql, parsedId.data);
    if (!plan) {
      reply.code(404);
      return { error: 'plan not found' };
    }
    return { plan };
  });

  // PATCH /api/plans/:id — update plan
  app.patch<{ Params: { id: string } }>('/api/plans/:id', async (req, reply) => {
    const parsedId = PlanIdParam.safeParse(req.params.id);
    if (!parsedId.success) {
      reply.code(400);
      return { error: 'invalid id' };
    }

    const parsed = UpdatePlanBody.safeParse(req.body);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'invalid body', details: parsed.error.flatten() };
    }

    const { title, description, status, progress_pct, items_total, items_completed, metadata } = parsed.data;
    const plan = await updatePlan(sql, parsedId.data, {
      title,
      description: description === null ? null : description,
      status,
      progressPct: progress_pct,
      itemsTotal: items_total,
      itemsCompleted: items_completed,
      metadata: metadata === null ? null : metadata,
    });

    if (!plan) {
      reply.code(404);
      return { error: 'plan not found' };
    }
    return { plan };
  });
}
