/**
 * DevKit Agents API
 * 
 * CRUD operations for agent management
 */

import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { PrismaClient } from '@prisma/client';
import { getRunStore } from '../runs/index.js';

const prisma = new PrismaClient();

interface CreateAgentBody {
  name: string;
  slug: string;
  description?: string;
  type: string;
  model: string;
  config?: any;
}

interface UpdateAgentBody {
  name?: string;
  slug?: string;
  description?: string;
  type?: string;
  model?: string;
  config?: any;
}

/**
 * Register agent management routes
 */
export function registerAgentRoutes(fastify: FastifyInstance) {
  /**
   * GET /devkit/api/agents
   * List all agents
   */
  fastify.get('/devkit/api/agents', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const agents = await prisma.devKitAgent.findMany({
        include: {
          tools: {
            include: {
              tool: true
            }
          }
        },
        orderBy: {
          createdAt: 'desc'
        }
      });

      // Transform to include tools count
      const agentsWithCount = agents.map(agent => ({
        ...agent,
        toolsCount: agent.tools.length,
        tools: agent.tools.map(at => at.tool)
      }));

      return {
        agents: agentsWithCount,
        total: agents.length
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_list_agents',
        message: error.message
      });
    }
  });

  /**
   * POST /devkit/api/agents
   * Create a new agent
   */
  fastify.post('/devkit/api/agents', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const body = request.body as CreateAgentBody;

      // Validate required fields
      if (!body.name || !body.slug || !body.type || !body.model) {
        return reply.status(400).send({
          error: 'validation_error',
          message: 'Missing required fields: name, slug, type, model'
        });
      }

      // Check if slug already exists
      const existing = await prisma.devKitAgent.findUnique({
        where: { slug: body.slug }
      });

      if (existing) {
        return reply.status(409).send({
          error: 'slug_exists',
          message: `Agent with slug '${body.slug}' already exists`
        });
      }

      // Create agent
      const agent = await prisma.devKitAgent.create({
        data: {
          name: body.name,
          slug: body.slug,
          description: body.description || null,
          type: body.type,
          model: body.model,
          config: body.config || {}
        },
        include: {
          tools: {
            include: {
              tool: true
            }
          }
        }
      });

      return {
        agent: {
          ...agent,
          toolsCount: agent.tools.length,
          tools: agent.tools.map(at => at.tool)
        }
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_create_agent',
        message: error.message
      });
    }
  });

  /**
   * GET /devkit/api/agents/:id
   * Get agent details
   */
  fastify.get('/devkit/api/agents/:id', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { id } = request.params as { id: string };

      const agent = await prisma.devKitAgent.findUnique({
        where: { id },
        include: {
          tools: {
            include: {
              tool: true
            }
          }
        }
      });

      if (!agent) {
        return reply.status(404).send({
          error: 'agent_not_found',
          message: `Agent with id '${id}' not found`
        });
      }

      return {
        agent: {
          ...agent,
          toolsCount: agent.tools.length,
          tools: agent.tools.map(at => ({
            ...at.tool,
            configOverride: at.configOverride
          }))
        }
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_get_agent',
        message: error.message
      });
    }
  });

  /**
   * PUT /devkit/api/agents/:id
   * Update agent
   */
  fastify.put('/devkit/api/agents/:id', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { id } = request.params as { id: string };
      const body = request.body as UpdateAgentBody;

      // Check if agent exists
      const existing = await prisma.devKitAgent.findUnique({
        where: { id }
      });

      if (!existing) {
        return reply.status(404).send({
          error: 'agent_not_found',
          message: `Agent with id '${id}' not found`
        });
      }

      // If slug is being updated, check for conflicts
      if (body.slug && body.slug !== existing.slug) {
        const slugExists = await prisma.devKitAgent.findUnique({
          where: { slug: body.slug }
        });

        if (slugExists) {
          return reply.status(409).send({
            error: 'slug_exists',
            message: `Agent with slug '${body.slug}' already exists`
          });
        }
      }

      // Update agent
      const agent = await prisma.devKitAgent.update({
        where: { id },
        data: {
          ...(body.name && { name: body.name }),
          ...(body.slug && { slug: body.slug }),
          ...(body.description !== undefined && { description: body.description }),
          ...(body.type && { type: body.type }),
          ...(body.model && { model: body.model }),
          ...(body.config && { config: body.config })
        },
        include: {
          tools: {
            include: {
              tool: true
            }
          }
        }
      });

      return {
        agent: {
          ...agent,
          toolsCount: agent.tools.length,
          tools: agent.tools.map(at => at.tool)
        }
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_update_agent',
        message: error.message
      });
    }
  });

  /**
   * DELETE /devkit/api/agents/:id
   * Delete agent
   */
  fastify.delete('/devkit/api/agents/:id', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { id } = request.params as { id: string };

      // Check if agent exists
      const existing = await prisma.devKitAgent.findUnique({
        where: { id }
      });

      if (!existing) {
        return reply.status(404).send({
          error: 'agent_not_found',
          message: `Agent with id '${id}' not found`
        });
      }

      // Delete agent (cascade will delete agent_tools)
      await prisma.devKitAgent.delete({
        where: { id }
      });

      return {
        success: true,
        message: 'Agent deleted successfully'
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_delete_agent',
        message: error.message
      });
    }
  });

  /**
   * POST /devkit/api/agents/:id/tools
   * Attach a tool to an agent
   */
  fastify.post('/devkit/api/agents/:id/tools', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { id } = request.params as { id: string };
      const body = request.body as { toolId: string; configOverride?: any };

      if (!body.toolId) {
        return reply.status(400).send({
          error: 'validation_error',
          message: 'toolId is required'
        });
      }

      // Check if agent exists
      const agent = await prisma.devKitAgent.findUnique({
        where: { id }
      });

      if (!agent) {
        return reply.status(404).send({
          error: 'agent_not_found',
          message: `Agent with id '${id}' not found`
        });
      }

      // Check if tool exists
      const tool = await prisma.devKitTool.findUnique({
        where: { id: body.toolId }
      });

      if (!tool) {
        return reply.status(404).send({
          error: 'tool_not_found',
          message: `Tool with id '${body.toolId}' not found`
        });
      }

      // Check if already attached
      const existing = await prisma.devKitAgentTool.findUnique({
        where: {
          agentId_toolId: {
            agentId: id,
            toolId: body.toolId
          }
        }
      });

      if (existing) {
        return reply.status(409).send({
          error: 'tool_already_attached',
          message: 'Tool is already attached to this agent'
        });
      }

      // Attach tool
      const agentTool = await prisma.devKitAgentTool.create({
        data: {
          agentId: id,
          toolId: body.toolId,
          configOverride: body.configOverride || null
        },
        include: {
          tool: true
        }
      });

      return {
        success: true,
        tool: agentTool.tool
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_attach_tool',
        message: error.message
      });
    }
  });

  /**
   * DELETE /devkit/api/agents/:id/tools/:toolId
   * Detach a tool from an agent
   */
  fastify.delete('/devkit/api/agents/:id/tools/:toolId', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { id, toolId } = request.params as { id: string; toolId: string };

      // Check if attachment exists
      const existing = await prisma.devKitAgentTool.findUnique({
        where: {
          agentId_toolId: {
            agentId: id,
            toolId: toolId
          }
        }
      });

      if (!existing) {
        return reply.status(404).send({
          error: 'attachment_not_found',
          message: 'Tool is not attached to this agent'
        });
      }

      // Detach tool
      await prisma.devKitAgentTool.delete({
        where: {
          agentId_toolId: {
            agentId: id,
            toolId: toolId
          }
        }
      });

      return {
        success: true,
        message: 'Tool detached successfully'
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_detach_tool',
        message: error.message
      });
    }
  });

  /**
   * POST /devkit/api/agents/:id/test-run
   * Run a test with this agent (DevKit only)
   */
  fastify.post('/devkit/api/agents/:id/test-run', async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { id } = request.params as { id: string };
      const body = request.body as { input?: any; tags?: string[]; clientToken?: string };

      // Check if agent exists
      const agent = await prisma.devKitAgent.findUnique({
        where: { id },
        include: {
          tools: {
            include: {
              tool: true
            }
          }
        }
      });

      if (!agent) {
        return reply.status(404).send({
          error: 'agent_not_found',
          message: `Agent with id '${id}' not found`
        });
      }

      // Create a run using the existing run store
      const runStore = getRunStore();
      const run = await runStore.createRun({
        name: `Test: ${agent.name}`,
        input: {
          ...(body.input || {}),
          _agent: {
            id: agent.id,
            name: agent.name,
            slug: agent.slug,
            type: agent.type,
            model: agent.model
          }
        },
        tags: [...(body.tags || []), 'devkit-test', `agent:${agent.slug}`],
        clientToken: body.clientToken ?? null
      });

      // Return run details with trimmed output
      const outputPreview = run.output 
        ? JSON.stringify(run.output).substring(0, 200) + (JSON.stringify(run.output).length > 200 ? '...' : '')
        : null;

      return {
        run: {
          id: run.id,
          status: run.status,
          createdAt: run.createdAt,
          outputPreview,
          agent: {
            id: agent.id,
            name: agent.name,
            slug: agent.slug
          }
        }
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'failed_to_create_test_run',
        message: error.message
      });
    }
  });
}

