import type { FastifyInstance } from "fastify";

import { executeMcpTool } from "../mcp/tool-runtime.js";
import type { AgentsRepository } from "../repositories/agents.js";
import type { TaskerClient } from "../tasker/client.js";
import { authenticateAgent } from "./session.js";

type ToolRouteDeps = {
  agentsRepository: AgentsRepository | null;
  taskerClient: TaskerClient;
};

export async function registerToolRoutes(app: FastifyInstance, deps: ToolRouteDeps): Promise<void> {
  app.post("/api/v1/tools/projects", async (request) => {
    const session = await authenticateAgent(request, deps);
    const result = await executeMcpTool(session, "tasker_create_project", request.body, deps, toolOptions(request));
    return result.structuredContent;
  });

  app.get("/api/v1/tools/projects", async (request) => {
    const session = await authenticateAgent(request, deps);
    const result = await executeMcpTool(session, "tasker_list_projects", {}, deps, toolOptions(request));
    return result.structuredContent;
  });

  app.get("/api/v1/tools/projects/:projectId/context", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { projectId: string };
    const query = request.query as { workspace_slug?: string };
    const result = await executeMcpTool(
      session,
      "tasker_get_project_context",
      {
        project_id: params.projectId,
        workspace_slug: query.workspace_slug,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.post("/api/v1/tools/projects/:projectId/labels/ensure", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { projectId: string };
    const result = await executeMcpTool(
      session,
      "tasker_ensure_labels",
      {
        ...requestBodyRecord(request.body),
        project_id: params.projectId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.get("/api/v1/tools/issues", async (request) => {
    const session = await authenticateAgent(request, deps);
    const query = request.query as { project_id?: string; workspace_slug?: string; query?: string };
    const result = await executeMcpTool(session, "tasker_search_issues", query, deps, toolOptions(request));
    return result.structuredContent;
  });

  app.post("/api/v1/tools/issues", async (request) => {
    const session = await authenticateAgent(request, deps);
    const result = await executeMcpTool(session, "tasker_create_issue", request.body, deps, toolOptions(request));
    return result.structuredContent;
  });

  app.get("/api/v1/tools/issues/:issueId", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const query = request.query as { project_id?: string; workspace_slug?: string };
    const result = await executeMcpTool(
      session,
      "tasker_get_issue",
      { ...query, issue_id: params.issueId },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.patch("/api/v1/tools/issues/:issueId", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const result = await executeMcpTool(
      session,
      "tasker_update_issue",
      {
        ...requestBodyRecord(request.body),
        issue_id: params.issueId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.post("/api/v1/tools/issues/:issueId/move", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const result = await executeMcpTool(
      session,
      "tasker_move_issue",
      {
        ...requestBodyRecord(request.body),
        issue_id: params.issueId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.post("/api/v1/tools/issues/:issueId/comments", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const result = await executeMcpTool(
      session,
      "tasker_append_comment",
      {
        ...requestBodyRecord(request.body),
        issue_id: params.issueId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.post("/api/v1/tools/issues/:issueId/attachments", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const result = await executeMcpTool(
      session,
      "tasker_attach_file",
      {
        ...requestBodyRecord(request.body),
        issue_id: params.issueId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.put("/api/v1/tools/issues/:issueId/labels", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const result = await executeMcpTool(
      session,
      "tasker_set_issue_labels",
      {
        ...requestBodyRecord(request.body),
        issue_id: params.issueId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });

  app.put("/api/v1/tools/issues/:issueId/assignees", async (request) => {
    const session = await authenticateAgent(request, deps);
    const params = request.params as { issueId: string };
    const result = await executeMcpTool(
      session,
      "tasker_assign_issue",
      {
        ...requestBodyRecord(request.body),
        issue_id: params.issueId,
      },
      deps,
      toolOptions(request)
    );
    return result.structuredContent;
  });
}

function toolOptions(request: { headers: Record<string, string | string[] | undefined> }): { source: "rest"; idempotencyKey: string | null } {
  return {
    source: "rest",
    idempotencyKey: readHeader(request.headers["idempotency-key"]),
  };
}

function requestBodyRecord(body: unknown): Record<string, unknown> {
  if (typeof body === "object" && body !== null && !Array.isArray(body)) {
    return body as Record<string, unknown>;
  }

  return {};
}

function readHeader(value: string | string[] | undefined): string | null {
  if (Array.isArray(value)) {
    return value[0] ?? null;
  }

  return value ?? null;
}
