/**
 * Conversation Router — inter-agent communication procedures
 */

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

export function conversationProcedures(publicProcedure: ProcedureBuilder) {
  return {
    createConversation: publicProcedure
      .input(z.object({
        fromAgentId: z.string().min(1),
        toAgentId: z.string().min(1).optional(),
        phaseId: z.string().min(1).optional(),
        taskId: z.string().min(1).optional(),
        question: z.string().min(1),
      }))
      .mutation(async ({ ctx, input }) => {
        const repo = requireConversationRepository(ctx);
        const agentManager = requireAgentManager(ctx);

        let toAgentId = input.toAgentId;

        // Resolve target agent from taskId
        if (!toAgentId && input.taskId) {
          const agents = await agentManager.list();
          const match = agents.find(a => a.taskId === input.taskId && a.status === 'running');
          if (!match) {
            throw new TRPCError({
              code: 'NOT_FOUND',
              message: `No running agent found for task '${input.taskId}'`,
            });
          }
          toAgentId = match.id;
        }

        // Resolve target agent from phaseId
        if (!toAgentId && input.phaseId) {
          const taskRepo = requireTaskRepository(ctx);
          const tasks = await taskRepo.findByPhaseId(input.phaseId);
          const taskIds = new Set(tasks.map(t => t.id));
          const agents = await agentManager.list();
          const match = agents.find(a => a.taskId && taskIds.has(a.taskId) && a.status === 'running');
          if (!match) {
            throw new TRPCError({
              code: 'NOT_FOUND',
              message: `No running agent found for phase '${input.phaseId}'`,
            });
          }
          toAgentId = match.id;
        }

        if (!toAgentId) {
          throw new TRPCError({
            code: 'BAD_REQUEST',
            message: 'Must provide toAgentId, taskId, or phaseId to identify target agent',
          });
        }

        const conversation = await repo.create({
          fromAgentId: input.fromAgentId,
          toAgentId,
          initiativeId: null,
          phaseId: input.phaseId ?? null,
          taskId: input.taskId ?? null,
          question: input.question,
        });

        ctx.eventBus.emit({
          type: 'conversation:created' as const,
          timestamp: new Date(),
          payload: {
            conversationId: conversation.id,
            fromAgentId: input.fromAgentId,
            toAgentId,
          },
        });

        return conversation;
      }),

    getPendingConversations: publicProcedure
      .input(z.object({
        agentId: z.string().min(1),
      }))
      .query(async ({ ctx, input }) => {
        const repo = requireConversationRepository(ctx);
        return repo.findPendingForAgent(input.agentId);
      }),

    getConversation: publicProcedure
      .input(z.object({
        id: z.string().min(1),
      }))
      .query(async ({ ctx, input }) => {
        const repo = requireConversationRepository(ctx);
        return repo.findById(input.id);
      }),

    answerConversation: publicProcedure
      .input(z.object({
        id: z.string().min(1),
        answer: z.string().min(1),
      }))
      .mutation(async ({ ctx, input }) => {
        const repo = requireConversationRepository(ctx);
        const existing = await repo.findById(input.id);
        if (!existing) {
          throw new TRPCError({
            code: 'NOT_FOUND',
            message: `Conversation '${input.id}' not found`,
          });
        }
        if (existing.status === 'answered') {
          throw new TRPCError({
            code: 'BAD_REQUEST',
            message: `Conversation '${input.id}' is already answered`,
          });
        }

        const updated = await repo.answer(input.id, input.answer);

        ctx.eventBus.emit({
          type: 'conversation:answered' as const,
          timestamp: new Date(),
          payload: {
            conversationId: input.id,
            fromAgentId: existing.fromAgentId,
            toAgentId: existing.toAgentId,
          },
        });

        return updated;
      }),
  };
}
