import type { FastifyInstance } from "fastify";
import type { MultipartFile } from "@fastify/multipart";
import { z } from "zod";
import { requireSession } from "../../lib/auth.js";
import {
  answerPortalQuestion,
  createWorkflowPortalLink,
  getPortalQuestionnaireByToken,
  previewWorkflowPortalLink,
  uploadPortalDocument,
} from "../../lib/intelligence.js";
import { getSessionProfile } from "../../lib/session.js";

const tokenSchema = z.object({
  token: z.string().min(10),
});

const answerSchema = z.object({
  questionId: z.string().uuid(),
  answerText: z.string().min(1),
});

const createWorkflowPortalSchema = z.object({
  clientId: z.string().uuid(),
  caseId: z.string().uuid(),
  workflowTemplateIds: z.array(z.string().uuid()).min(1).max(25),
});

function getMultipartFieldValue(
  fields: Record<string, MultipartFile["fields"][string]>,
  key: string,
) {
  const field = fields[key];

  if (!field || Array.isArray(field) || !("value" in field)) {
    return "";
  }

  return String(field.value ?? "");
}

export async function registerPortalRoutes(app: FastifyInstance) {
  app.post("/links/workflow/preview", async (request, reply) => {
    const session = await requireSession(request, reply);
    const profile = await getSessionProfile(session);
    const payload = createWorkflowPortalSchema.parse(request.body);

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

    return previewWorkflowPortalLink({
      lawFirmId: profile.lawFirm.id,
      clientId: payload.clientId,
      caseId: payload.caseId,
      actorUserId: profile.user.id,
      workflowTemplateIds: payload.workflowTemplateIds,
    });
  });

  app.post("/links/workflow", async (request, reply) => {
    const session = await requireSession(request, reply);
    const profile = await getSessionProfile(session);
    const payload = createWorkflowPortalSchema.parse(request.body);

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

    return createWorkflowPortalLink({
      lawFirmId: profile.lawFirm.id,
      clientId: payload.clientId,
      caseId: payload.caseId,
      actorUserId: profile.user.id,
      workflowTemplateIds: payload.workflowTemplateIds,
    });
  });

  app.get("/questionnaires/:token", async (request, reply) => {
    const { token } = tokenSchema.parse(request.params);

    try {
      return await getPortalQuestionnaireByToken(token);
    } catch (error) {
      throw reply.notFound(error instanceof Error ? error.message : "Questionnaire not found");
    }
  });

  app.post("/questionnaires/:token/answers", async (request, reply) => {
    const { token } = tokenSchema.parse(request.params);
    const payload = answerSchema.parse(request.body);

    return answerPortalQuestion({
      token,
      questionId: payload.questionId,
      answerText: payload.answerText,
    });
  });

  app.post("/questionnaires/:token/documents", async (request, reply) => {
    const { token } = tokenSchema.parse(request.params);
    const multipartRequest = request as typeof request & {
      file: () => Promise<MultipartFile | undefined>;
    };
    const file = await multipartRequest.file();

    if (!file) {
      throw reply.badRequest("A file upload is required");
    }

    const requiredDocumentId = getMultipartFieldValue(file.fields, "requiredDocumentId");
    const title = getMultipartFieldValue(file.fields, "title") || file.filename;
    const providedText = getMultipartFieldValue(file.fields, "textContent");

    if (!requiredDocumentId) {
      throw reply.badRequest("requiredDocumentId is required");
    }

    const buffer = await file.toBuffer();
    const textContent =
      providedText ||
      (file.mimetype.startsWith("text/") ? buffer.toString("utf8") : "");

    return uploadPortalDocument({
      token,
      requiredDocumentId,
      title,
      originalFileName: file.filename,
      mimeType: file.mimetype,
      fileBuffer: buffer,
      textContent: textContent || null,
    });
  });
}
