/**
 * Task Router — CRUD, approval, listing by parent/initiative/phase
 */

import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import type { ProcedureBuilder } from '../trpc.js';
import {
  requireTaskRepository,
  requireInitiativeRepository,
  requirePhaseRepository,
  requireDispatchManager,
} from './_helpers.js';

export function taskProcedures(publicProcedure: ProcedureBuilder) {
  return {
    listTasks: publicProcedure
      .input(z.object({ parentTaskId: z.string().min(1) }))
      .query(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        return taskRepository.findByParentTaskId(input.parentTaskId);
      }),

    getTask: publicProcedure
      .input(z.object({ id: z.string().min(1) }))
      .query(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        const task = await taskRepository.findById(input.id);
        if (!task) {
          throw new TRPCError({
            code: 'NOT_FOUND',
            message: `Task '${input.id}' not found`,
          });
        }
        return task;
      }),

    updateTaskStatus: publicProcedure
      .input(z.object({
        id: z.string().min(1),
        status: z.enum(['pending_approval', 'pending', 'in_progress', 'completed', 'blocked']),
      }))
      .mutation(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        const existing = await taskRepository.findById(input.id);
        if (!existing) {
          throw new TRPCError({
            code: 'NOT_FOUND',
            message: `Task '${input.id}' not found`,
          });
        }
        return taskRepository.update(input.id, { status: input.status });
      }),

    createInitiativeTask: publicProcedure
      .input(z.object({
        initiativeId: z.string().min(1),
        name: z.string().min(1),
        description: z.string().optional(),
        category: z.enum(['execute', 'research', 'discuss', 'plan', 'detail', 'refine', 'verify', 'merge', 'review']).optional(),
        type: z.enum(['auto', 'checkpoint:human-verify', 'checkpoint:decision', 'checkpoint:human-action']).optional(),
        requiresApproval: z.boolean().nullable().optional(),
      }))
      .mutation(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        const initiativeRepo = requireInitiativeRepository(ctx);

        const initiative = await initiativeRepo.findById(input.initiativeId);
        if (!initiative) {
          throw new TRPCError({
            code: 'NOT_FOUND',
            message: `Initiative '${input.initiativeId}' not found`,
          });
        }

        return taskRepository.create({
          initiativeId: input.initiativeId,
          name: input.name,
          description: input.description ?? null,
          category: input.category ?? 'execute',
          type: input.type ?? 'auto',
          requiresApproval: input.requiresApproval ?? null,
          status: 'pending',
        });
      }),

    createPhaseTask: publicProcedure
      .input(z.object({
        phaseId: z.string().min(1),
        name: z.string().min(1),
        description: z.string().optional(),
        category: z.enum(['execute', 'research', 'discuss', 'plan', 'detail', 'refine', 'verify', 'merge', 'review']).optional(),
        type: z.enum(['auto', 'checkpoint:human-verify', 'checkpoint:decision', 'checkpoint:human-action']).optional(),
        requiresApproval: z.boolean().nullable().optional(),
      }))
      .mutation(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        const phaseRepo = requirePhaseRepository(ctx);

        const phase = await phaseRepo.findById(input.phaseId);
        if (!phase) {
          throw new TRPCError({
            code: 'NOT_FOUND',
            message: `Phase '${input.phaseId}' not found`,
          });
        }

        return taskRepository.create({
          phaseId: input.phaseId,
          name: input.name,
          description: input.description ?? null,
          category: input.category ?? 'execute',
          type: input.type ?? 'auto',
          requiresApproval: input.requiresApproval ?? null,
          status: 'pending',
        });
      }),

    listPendingApprovals: publicProcedure
      .input(z.object({
        initiativeId: z.string().optional(),
        phaseId: z.string().optional(),
        category: z.enum(['execute', 'research', 'discuss', 'plan', 'detail', 'refine', 'verify', 'merge', 'review']).optional(),
      }).optional())
      .query(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        return taskRepository.findPendingApproval(input);
      }),

    listInitiativeTasks: publicProcedure
      .input(z.object({ initiativeId: z.string().min(1) }))
      .query(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        const tasks = await taskRepository.findByInitiativeId(input.initiativeId);
        return tasks.filter((t) => t.category !== 'detail');
      }),

    listPhaseTasks: publicProcedure
      .input(z.object({ phaseId: z.string().min(1) }))
      .query(async ({ ctx, input }) => {
        const taskRepository = requireTaskRepository(ctx);
        const tasks = await taskRepository.findByPhaseId(input.phaseId);
        return tasks.filter((t) => t.category !== 'detail');
      }),

    approveTask: publicProcedure
      .input(z.object({ taskId: z.string().min(1) }))
      .mutation(async ({ ctx, input }) => {
        const dispatchManager = requireDispatchManager(ctx);
        await dispatchManager.approveTask(input.taskId);
        return { success: true };
      }),
  };
}
