import type { Prisma } from "@/generated/prisma/client";
import { prisma } from "@/lib/prisma";
import { sendAlertMailWithGraph } from "@/services/alertes-mail-graph.service";
import {
  buildMailHtml,
  type GraphAttachment,
  loadSenderSignature,
  loadSignatureLogo,
} from "@/services/mail-rendering.service";
import { generateProcedurePdf } from "@/services/procedures-pdf.service";
import { getProcedureById } from "@/services/procedures.service";

type ProcedureForEmail = NonNullable<
  Awaited<ReturnType<typeof getProcedureById>>
>;

type ProcedureRhRecipient = {
  id: number;
  label: string;
  email: string;
};

const REQUEST_LABELS: Record<string, string> = {
  DEMANDE_NOUVELLES: "Demande de nouvelles",
  LETTRE_RECADRAGE: "Lettre de recadrage",
  AVERTISSEMENT_DIRECT: "Avertissement direct",
  CONVOCATION_SANCTION: "Convocation entretien préalable à une sanction",
  CONVOCATION_LICENCIEMENT_RUPTURE:
    "Convocation entretien préalable à un licenciement ou rupture anticipée du contrat",
  AUTRE: "Autre",
};

function employeeName(procedure: ProcedureForEmail) {
  return [procedure.employee.TIT, procedure.employee.NSA, procedure.employee.PRE]
    .filter(Boolean)
    .join(" ");
}

function attachmentName(procedure: ProcedureForEmail) {
  const safeName = [procedure.employee.NSA, procedure.employee.PRE]
    .filter(Boolean)
    .join("-")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-zA-Z0-9-]+/g, "-")
    .replace(/^-+|-+$/g, "");
  return `demande-procedure-${safeName || procedure.employee_cos}-${procedure.id}.pdf`;
}

function snapshot(value: unknown): Prisma.InputJsonValue {
  return JSON.parse(JSON.stringify(value)) as Prisma.InputJsonValue;
}

export async function sendProcedureToRh(input: {
  procedure: ProcedureForEmail;
  recipient: ProcedureRhRecipient;
  senderUserId: number;
  senderName: string;
  senderEmail: string | null;
}) {
  const { procedure, recipient } = input;
  const name = employeeName(procedure);
  const requestType =
    procedure.request_type === "AUTRE"
      ? procedure.other_type || REQUEST_LABELS.AUTRE
      : REQUEST_LABELS[procedure.request_type] || procedure.request_type;
  const subject = `[RH Connect] Demande de procédure n°${procedure.id} — ${name}`;
  const bodyText = [
    `Bonjour ${recipient.label},`,
    "",
    `Veuillez trouver en pièce jointe la demande de procédure n°${procedure.id} concernant ${name} (COS ${procedure.employee_cos}).`,
    "",
    `Type de demande : ${requestType}`,
    `Responsable hiérarchique : ${procedure.manager_name}`,
    `Demande enregistrée le : ${procedure.created_at.toLocaleDateString("fr-FR", { timeZone: "Europe/Paris" })}`,
    "",
    `Envoi effectué depuis RH Connect par ${input.senderName}${input.senderEmail ? ` (${input.senderEmail})` : ""}.`,
  ].join("\n");
  const pdfName = attachmentName(procedure);
  const pdf = await generateProcedurePdf(procedure);

  const communication = await prisma.employee_communications.create({
    data: {
      employee_cos: procedure.employee_cos,
      channel: "EMAIL_RH",
      recipient: recipient.email,
      subject,
      body_text: bodyText,
      procedure_request_id: procedure.id,
      attachment_name: pdfName,
      status: "PROCESSING",
      sent_by_user_id: input.senderUserId,
    },
  });

  try {
    const signature = await loadSenderSignature(input.senderUserId);
    const logoAttachment = await loadSignatureLogo(signature);
    const attachments: GraphAttachment[] = [
      {
        name: pdfName,
        contentType: "application/pdf",
        contentBytes: pdf.toString("base64"),
      },
    ];
    if (logoAttachment) attachments.push(logoAttachment);

    const result = await sendAlertMailWithGraph({
      recipients: [recipient.email],
      subject,
      html: buildMailHtml(bodyText, signature, Boolean(logoAttachment)),
      attachments,
    });

    const now = new Date();
    await prisma.$transaction([
      prisma.employee_communications.update({
        where: { id: communication.id },
        data: {
          status: "SENT",
          provider_message_id: result.messageId,
          error_message: null,
          sent_at: now,
        },
      }),
      prisma.procedure_request_history.create({
        data: {
          procedure_request_id: procedure.id,
          action: "ENVOI_RH",
          summary: `Demande envoyée à ${recipient.label} (${recipient.email})`,
          snapshot: snapshot({
            communicationId: communication.id,
            recipientId: recipient.id,
            recipient: recipient.email,
            status: "SENT",
          }),
          created_by_user_id: input.senderUserId,
        },
      }),
    ]);

    return { communicationId: communication.id, sentAt: now };
  } catch (error) {
    console.error("[procedure-rh-email] Échec de l’envoi Graph", error);
    await prisma.$transaction([
      prisma.employee_communications.update({
        where: { id: communication.id },
        data: {
          status: "FAILED",
          error_message: String(error).slice(0, 2_000),
        },
      }),
      prisma.procedure_request_history.create({
        data: {
          procedure_request_id: procedure.id,
          action: "ECHEC_ENVOI_RH",
          summary: `Échec de l’envoi à ${recipient.label} (${recipient.email})`,
          snapshot: snapshot({
            communicationId: communication.id,
            recipientId: recipient.id,
            recipient: recipient.email,
            status: "FAILED",
          }),
          created_by_user_id: input.senderUserId,
        },
      }),
    ]);
    throw error;
  }
}
