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);

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

    let requiredDocumentId = "";
    let title = "";
    let providedText = "";
    const uploads: Array<{
      documentRecordId: string;
      originalFileName: string;
      title: string;
    }> = [];
    let sessionResponse = null as Awaited<ReturnType<typeof uploadPortalDocument>> | null;

    for await (const part of request.parts()) {
      if (part.type === "field") {
        const value = String(part.value ?? "").trim();

        if (part.fieldname === "requiredDocumentId") {
          requiredDocumentId = value;
        } else if (part.fieldname === "title") {
          title = value;
        } else if (part.fieldname === "textContent") {
          providedText = value;
        }

        continue;
      }

      const resolvedRequiredDocumentId =
        requiredDocumentId || getMultipartFieldValue(part.fields, "requiredDocumentId");
      const resolvedTitle = title || getMultipartFieldValue(part.fields, "title") || part.filename;
      const resolvedProvidedText =
        providedText || getMultipartFieldValue(part.fields, "textContent");

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

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

      sessionResponse = await uploadPortalDocument({
        token,
        requiredDocumentId: resolvedRequiredDocumentId,
        title: resolvedTitle,
        originalFileName: part.filename,
        mimeType: part.mimetype,
        fileBuffer: buffer,
        textContent: textContent || null,
      });

      uploads.push({
        documentRecordId: sessionResponse.documentRecordId,
        originalFileName: part.filename,
        title: resolvedTitle,
      });
    }

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

    return {
      documentRecordId: sessionResponse.documentRecordId,
      documentRecordIds: uploads.map((item) => item.documentRecordId),
      uploadedCount: uploads.length,
      uploads,
      remainingPending: sessionResponse.remainingPending,
      session: sessionResponse.session,
    };
  });
}
