import type { FastifyInstance } from "fastify";

import { DatabaseNotConfiguredError } from "../db/pool.js";
import type { AgentsRepository } from "../repositories/agents.js";
import { parseBearerToken } from "../security/bearer.js";

const MCP_PROTOCOL_VERSION = "2025-06-18";

type OntologyRouteDeps = {
  agentsRepository: AgentsRepository | null;
  ontologyCoreUrl: string;
  ontologyCoreAccessToken?: string;
};

export async function registerOntologyGatewayRoutes(app: FastifyInstance, deps: OntologyRouteDeps): Promise<void> {
  app.post("/ontology-mcp", async (request, reply) => {
    if (!deps.agentsRepository) {
      throw new DatabaseNotConfiguredError();
    }

    const token = parseBearerToken(request.headers.authorization);
    const session = await deps.agentsRepository.findActiveSessionByToken(token, "ontology");
    if (!session) {
      return reply.status(401).send({
        ok: false,
        error: "ontology_agent_unauthorized",
        message: "Ontology token is inactive, expired, revoked, or has the wrong purpose.",
      });
    }

    const upstreamToken = deps.ontologyCoreAccessToken;
    if (!upstreamToken) {
      return reply.status(503).send({
        ok: false,
        error: "ontology_proxy_not_configured",
        message: "Ontology Core access token is not configured.",
      });
    }

    let upstream: Response;
    try {
      upstream = await fetch(new URL("/mcp", deps.ontologyCoreUrl), {
        method: "POST",
        redirect: "manual",
        headers: {
          Accept: readHeader(request.headers.accept) ?? "application/json, text/event-stream",
          Authorization: `Bearer ${upstreamToken}`,
          "Content-Type": "application/json",
          "MCP-Protocol-Version": readHeader(request.headers["mcp-protocol-version"]) ?? MCP_PROTOCOL_VERSION,
        },
        body: JSON.stringify(request.body ?? {}),
        signal: AbortSignal.timeout(60_000),
      });
    } catch {
      return reply.status(503).send({
        ok: false,
        error: "ontology_proxy_unavailable",
        message: "Ontology Core MCP is unavailable.",
      });
    }

    const payload = await upstream.text();
    reply.status(upstream.status);
    reply.header("Cache-Control", "no-store");
    reply.header("Content-Type", upstream.headers.get("content-type") ?? "application/json; charset=utf-8");
    for (const header of ["mcp-protocol-version", "mcp-session-id", "vary"]) {
      const value = upstream.headers.get(header);
      if (value) {
        reply.header(header, value);
      }
    }
    return reply.send(payload);
  });
}

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