/**
 * ADR-0027: Admin routes for organization-scoped capability connections.
 * GET    /api/org/:orgSlug/capability-connections           — list all
 * GET    /api/org/:orgSlug/capability-connections/:capId    — read one
 * PUT    /api/org/:orgSlug/capability-connections/:capId    — rotate/create
 * DELETE /api/org/:orgSlug/capability-connections/:capId    — disable
 */
import type { PrismaClient } from "@prisma/client";
import type { FastifyInstance } from "fastify";
import { CapabilityConnectionService } from "../../capability/capabilityConnectionService.js";
import { CapabilityReadinessError, type CapabilityReadinessProbe } from "../../capability/capabilityReadiness.js";
import type { LocalSecretEnvelope } from "../../security/secretEnvelope.js";
import { requireOrgRole, type GuardDeps } from "../auth/guards.js";
import { handleRouteError } from "../errors.js";

export interface CapabilityConnectionRouteConfig {
  readonly prisma: PrismaClient;
  readonly sessionSecret: string;
  readonly secretEnvelope: LocalSecretEnvelope;
  readonly readinessProbe?: CapabilityReadinessProbe;
}

export async function registerCapabilityConnectionRoutes(
  app: FastifyInstance,
  config: CapabilityConnectionRouteConfig,
): Promise<void> {
  const guardDeps: GuardDeps = { prisma: config.prisma, sessionSecret: config.sessionSecret };
  const connections = new CapabilityConnectionService(
    config.prisma,
    config.secretEnvelope,
    config.readinessProbe,
  );

  app.get("/api/org/:orgSlug/capability-connections", async (request, reply) => {
    try {
      const { orgSlug } = request.params as { orgSlug: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      return { connections: await connections.list(auth.organization.id) };
    } catch (error) {
      request.log.error({ requestId: request.id, operation: "capability_connection.list" }, "list failed");
      return handleRouteError(reply, error);
    }
  });

  app.get("/api/org/:orgSlug/capability-connections/:capabilityId", async (request, reply) => {
    try {
      const { orgSlug, capabilityId } = request.params as { orgSlug: string; capabilityId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      return { connection: await connections.read(auth.organization.id, capabilityId) };
    } catch (error) {
      request.log.error({ requestId: request.id, operation: "capability_connection.read" }, "read failed");
      return handleRouteError(reply, error);
    }
  });

  app.put("/api/org/:orgSlug/capability-connections/:capabilityId", async (request, reply) => {
    try {
      const { orgSlug, capabilityId } = request.params as { orgSlug: string; capabilityId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      const body = parseBody(request.body);
      const result = await connections.rotate({
        organizationId: auth.organization.id,
        capabilityId,
        actorUserId: auth.user.id,
        ...body,
      });
      request.log.info({
        organizationId: auth.organization.id,
        capabilityId,
        connectionId: result.id,
        status: result.status,
        secretVersion: result.activeVersion,
      }, result.created ? "Capability Connection created" : "Capability Connection rotated");
      const { created, ...metadata } = result;
      return reply.status(created ? 201 : 200).send(metadata);
    } catch (error) {
      const facts = error instanceof CapabilityReadinessError
        ? {
            errorCode: error.code,
            failureCategory: error.category,
            ...(error.upstreamStatus !== undefined ? { upstreamStatus: error.upstreamStatus } : {}),
          }
        : { errorCode: "capability_connection_write_failed" };
      request.log.error({ requestId: request.id, operation: "capability_connection.rotate", ...facts }, "rotate failed");
      return handleRouteError(reply, error);
    }
  });

  app.delete("/api/org/:orgSlug/capability-connections/:capabilityId", async (request, reply) => {
    try {
      const { orgSlug, capabilityId } = request.params as { orgSlug: string; capabilityId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      const result = await connections.disable({
        organizationId: auth.organization.id,
        capabilityId,
        actorUserId: auth.user.id,
      });
      request.log.info({
        organizationId: auth.organization.id,
        capabilityId,
        connectionId: result.id,
        status: result.status,
      }, "Capability Connection disabled");
      return reply.send(result);
    } catch (error) {
      request.log.error({ requestId: request.id, operation: "capability_connection.disable" }, "disable failed");
      return handleRouteError(reply, error);
    }
  });
}

function parseBody(value: unknown): { readonly accessKeyId: string; readonly accessKeySecret: string; readonly endpoint: string } {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    throw new Error("invalid capability credential body");
  }
  const body = value as Record<string, unknown>;
  for (const name of ["accessKeyId", "accessKeySecret", "endpoint"] as const) {
    if (typeof body[name] !== "string" || (body[name] as string).trim() === "") {
      throw new Error(`${name} is required`);
    }
  }
  return {
    accessKeyId: body["accessKeyId"] as string,
    accessKeySecret: body["accessKeySecret"] as string,
    endpoint: body["endpoint"] as string,
  };
}
