import type { PrismaClient } from "@prisma/client";
import type { FastifyInstance } from "fastify";
import { FeishuApplicationConnectionService } from "../../connections/feishuApplicationConnections.js";
import { FeishuReadinessError, type FeishuReadinessProbe } from "../../connections/feishuReadiness.js";
import type { LocalSecretEnvelope } from "../../security/secretEnvelope.js";
import { requireOrgRole, type GuardDeps } from "../auth/guards.js";
import { handleRouteError } from "../errors.js";

export interface FeishuApplicationConnectionRouteConfig {
  readonly prisma: PrismaClient;
  readonly sessionSecret: string;
  readonly secretEnvelope: LocalSecretEnvelope;
  readonly readinessProbe?: FeishuReadinessProbe;
}

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

  app.get("/api/org/:orgSlug/feishu-application-connection", async (request, reply) => {
    try {
      const { orgSlug } = request.params as { orgSlug: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      return { connection: await connections.readMetadata(auth.organization.id) };
    } catch (error) {
      request.log.error({
        requestId: request.id,
        operation: "feishu_application_connection.read",
        errorCode: "feishu_application_connection_read_failed",
      }, "Feishu Application Connection read failed");
      return handleRouteError(reply, error);
    }
  });

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

  app.delete("/api/org/:orgSlug/feishu-application-connection", async (request, reply) => {
    try {
      const { orgSlug } = request.params as { orgSlug: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      const result = await connections.disable({
        organizationId: auth.organization.id,
        actorUserId: auth.user.id,
      });
      request.log.info({
        organizationId: auth.organization.id,
        connectionId: result.id,
        status: result.status,
        secretVersion: result.activeVersion,
        keyId: result.keyId,
      }, "Feishu Application Connection disabled");
      return reply.send(result);
    } catch (error) {
      request.log.error({
        requestId: request.id,
        operation: "feishu_application_connection.disable",
        errorCode: "feishu_application_connection_disable_failed",
      }, "Feishu Application Connection disable failed");
      return handleRouteError(reply, error);
    }
  });
}

function parseBody(value: unknown): {
  readonly appId: string;
  readonly appSecret: string;
  readonly botOpenId: string;
  readonly verificationToken?: string;
  readonly encryptKey?: string;
} {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    throw new Error("invalid Feishu Application credential body");
  }
  const body = value as Record<string, unknown>;
  for (const name of ["appId", "appSecret", "botOpenId"] as const) {
    if (typeof body[name] !== "string") throw new Error(`${name} is required`);
  }
  for (const name of ["verificationToken", "encryptKey"] as const) {
    if (body[name] !== undefined && typeof body[name] !== "string") {
      throw new Error(`${name} must be a string`);
    }
  }
  return {
    appId: body["appId"] as string,
    appSecret: body["appSecret"] as string,
    botOpenId: body["botOpenId"] as string,
    ...(body["verificationToken"] !== undefined
      ? { verificationToken: body["verificationToken"] as string }
      : {}),
    ...(body["encryptKey"] !== undefined ? { encryptKey: body["encryptKey"] as string } : {}),
  };
}
