import type { FastifyInstance } from "fastify";
import { z } from "zod";
import { requireSession } from "../../lib/auth.js";
import { writeAuditLog } from "../../lib/audit.js";
import { encryptSecret } from "../../lib/crypto.js";
import { createId } from "../../lib/id.js";
import { prisma } from "../../lib/prisma.js";
import { getSessionProfile } from "../../lib/session.js";

const aiCredentialSchema = z.object({
  provider: z.string().min(2).max(50).default("openai"),
  credentialName: z.string().min(2).max(100),
  apiKey: z.string().min(20).max(400),
  defaultModel: z.string().min(2).max(100).default("gpt-5.4"),
  rateLimitPerMinute: z.coerce.number().int().positive().optional(),
  monthlyBudget: z.coerce.number().positive().optional(),
  alertThreshold: z.coerce.number().positive().max(100).optional(),
  setAsDefault: z.boolean().default(true),
});

export async function registerAiRoutes(app: FastifyInstance) {
  app.get("/settings", async (request, reply) => {
    const session = await requireSession(request, reply);
    const profile = await getSessionProfile(session);

    if (!profile) {
      throw reply.unauthorized("Session is no longer valid");
    }

    const [settings, credentials] = await prisma.$transaction([
      prisma.lawFirmAiSetting.findUnique({
        where: {
          law_firm_id: profile.lawFirm.id,
        },
      }),
      prisma.lawFirmAiCredential.findMany({
        where: {
          law_firm_id: profile.lawFirm.id,
        },
        orderBy: {
          created_at: "desc",
        },
      }),
    ]);

    return {
      settings,
      credentials: credentials.map((credential) => ({
        id: credential.id,
        provider: credential.provider,
        credentialName: credential.credential_name,
        keyLast4: credential.key_last4,
        isActive: credential.is_active,
        isDefault: credential.is_default,
        createdAt: credential.created_at,
      })),
    };
  });

  app.post("/credentials", async (request, reply) => {
    const session = await requireSession(request, reply);
    const profile = await getSessionProfile(session);

    if (!profile) {
      throw reply.unauthorized("Session is no longer valid");
    }

    const payload = aiCredentialSchema.parse(request.body);
    const encryptedApiKey = encryptSecret(payload.apiKey);
    const keyLast4 = payload.apiKey.slice(-4);
    const credentialId = createId();

    const result = await prisma.$transaction(async (tx) => {
      if (payload.setAsDefault) {
        await tx.lawFirmAiCredential.updateMany({
          where: {
            law_firm_id: profile.lawFirm.id,
            provider: payload.provider,
          },
          data: {
            is_default: false,
          },
        });
      }

      const credential = await tx.lawFirmAiCredential.create({
        data: {
          id: credentialId,
          law_firm_id: profile.lawFirm.id,
          provider: payload.provider,
          credential_name: payload.credentialName,
          encrypted_api_key: encryptedApiKey,
          encryption_key_version: "v1",
          key_last4: keyLast4,
          is_active: true,
          is_default: payload.setAsDefault,
          created_by_user_id: profile.user.id,
        },
      });

      const settings = await tx.lawFirmAiSetting.upsert({
        where: {
          law_firm_id: profile.lawFirm.id,
        },
        update: {
          default_provider: payload.provider,
          default_model: payload.defaultModel,
          active_credential_id: payload.setAsDefault ? credentialId : undefined,
          rate_limit_per_minute: payload.rateLimitPerMinute,
          monthly_budget: payload.monthlyBudget,
          alert_threshold: payload.alertThreshold,
          is_active: true,
        },
        create: {
          id: createId(),
          law_firm_id: profile.lawFirm.id,
          default_provider: payload.provider,
          default_model: payload.defaultModel,
          active_credential_id: payload.setAsDefault ? credentialId : null,
          rate_limit_per_minute: payload.rateLimitPerMinute,
          monthly_budget: payload.monthlyBudget,
          alert_threshold: payload.alertThreshold,
          is_active: true,
        },
      });

      return { credential, settings };
    });

    await writeAuditLog({
      lawFirmId: profile.lawFirm.id,
      officeId: profile.user.primaryOfficeId ?? null,
      actorUserId: profile.user.id,
      entityType: "law_firm_ai_credential",
      entityId: result.credential.id,
      action: "ai.credential.create",
      afterJson: {
        provider: result.credential.provider,
        credentialName: result.credential.credential_name,
        keyLast4: result.credential.key_last4,
        isDefault: result.credential.is_default,
      },
      request,
    });

    return reply.code(201).send({
      id: result.credential.id,
      provider: result.credential.provider,
      credentialName: result.credential.credential_name,
      keyLast4: result.credential.key_last4,
      isActive: result.credential.is_active,
      isDefault: result.credential.is_default,
      defaultModel: result.settings.default_model,
    });
  });
}
