import path from "node:path";

import PDFDocument from "pdfkit";

import type {
  AttestationEmploiPdfData,
  AttestationMutuellePdfData,
  AttestationProlongationMutuellePdfData,
  AutorisationPrefecturePdfData,
} from "@/services/impressions.service";

type Pdf = InstanceType<typeof PDFDocument>;

const regularFontPath = () =>
  path.join(process.cwd(), "public", "fonts", "DejaVuSans.ttf");
const boldFontPath = () =>
  path.join(process.cwd(), "public", "fonts", "DejaVuSans-Bold.ttf");

function formatLongFrenchDate(value: string) {
  const [year, month, day] = value.split("-").map(Number);
  if (!year || !month || !day) return value;

  const formatted = new Intl.DateTimeFormat("fr-FR", {
    timeZone: "Europe/Paris",
    day: "numeric",
    month: "long",
    year: "numeric",
  }).format(new Date(Date.UTC(year, month - 1, day, 12)));
  return day === 1 ? formatted.replace(/^1 /, "1er ") : formatted;
}

function createDocument(title: string) {
  const document = new PDFDocument({
    size: "A4",
    margins: { top: 0, right: 0, bottom: 0, left: 0 },
    font: regularFontPath(),
    info: { Title: title, Author: "RH Connect" },
    compress: true,
  });
  document.registerFont("DocumentRegular", regularFontPath());
  document.registerFont("DocumentBold", boldFontPath());
  return document;
}

function toBuffer(draw: (document: Pdf) => void, title: string) {
  return new Promise<Buffer>((resolve, reject) => {
    const chunks: Buffer[] = [];
    const document = createDocument(title);
    document.on("data", (chunk: Buffer) => chunks.push(chunk));
    document.on("end", () => resolve(Buffer.concat(chunks)));
    document.on("error", reject);
    draw(document);
    document.end();
  });
}

function drawAttestationTitle(document: Pdf) {
  const margin = 72;
  const width = document.page.width - margin * 2;
  document.lineWidth(0.75).rect(margin, 218, width, 24).stroke("#111111");
  document
    .font("DocumentBold")
    .fontSize(15)
    .fillColor("#111111")
    .text("ATTESTATION", margin, 222, { width, align: "center" });
}

function drawSignature(
  document: Pdf,
  data: {
    lieuDocument: string;
    dateDocument: string;
    signataireNom: string;
    signataireFonction: string;
  },
  minimumY = 552,
) {
  const margin = 72;
  const width = 225;
  const x = document.page.width - margin - width;
  const y = Math.max(minimumY, document.y + 48);
  document
    .font("DocumentRegular")
    .fontSize(11.5)
    .text(
      `Fait à ${data.lieuDocument},\nLe ${formatLongFrenchDate(data.dateDocument)}.`,
      x,
      y,
      { width, align: "right", lineGap: 2 },
    );
  document.text(
    `${data.signataireNom}\n${data.signataireFonction}`,
    x - 40,
    y + 70,
    { width: width + 40, align: "right", lineGap: 2 },
  );
}

function qualitePoste(poste: string) {
  const letter = poste
    .trim()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .charAt(0)
    .toLowerCase();
  return "aeiouyh".includes(letter) ? `d'${poste}` : `de ${poste}`;
}

function employmentSentence(data: AttestationMutuellePdfData) {
  const start = formatLongFrenchDate(data.dateEmbauche);
  if (data.estToujoursDansEffectifs) {
    return `${data.titreNomPrenom} ${data.domicilie} ${data.adresseLigne} travaille au sein de notre société en ${data.typeContrat} depuis le ${start} en qualité ${qualitePoste(data.poste)} et est toujours dans nos effectifs à ce jour.`;
  }
  const end = data.dateFinContrat
    ? ` au ${formatLongFrenchDate(data.dateFinContrat)}`
    : "";
  return `${data.titreNomPrenom} ${data.domicilie} ${data.adresseLigne} a travaillé au sein de notre société en ${data.typeContrat} du ${start}${end} en qualité ${qualitePoste(data.poste)}.`;
}

export function renderAttestationEmploiPdf(data: AttestationEmploiPdfData) {
  return toBuffer((document) => {
    drawAttestationTitle(document);
    const margin = 76;
    const width = document.page.width - margin * 2;
    document
      .font("DocumentRegular")
      .fontSize(11.5)
      .text(
        `Je ${data.formuleSoussignataire}, ${data.signataireNom} - ${data.signataireFonction} de la ${data.entreprise}, atteste par la présente que ${data.titreNomPrenom} ${data.domicilie} ${data.adresseLigne}, a effectué les contrats suivants au sein de notre société :`,
        margin,
        314,
        { width, align: "justify", lineGap: 2.5 },
      );
    document
      .font("DocumentRegular")
      .fontSize(10.5)
      .text(data.contratsTexte, margin + 24, document.y + 24, {
        width: width - 48,
        lineGap: 5,
      });
    document
      .fontSize(11.5)
      .text("Pour faire et valoir ce que de droit.", 108, document.y + 36);
    drawSignature(document, data, 575);
  }, `Attestation d'emploi - ${data.titreNomPrenom}`);
}

const MUTUELLE_LEGAL_TEXT = [
  "Décret n° 2015-1883 du 30 décembre 2015 pris pour l'application de l'article 34 de la loi n° 2015-1702 du 21 décembre 2015 de financement de la sécurité sociale pour 2016 :",
  "L'article D. 911-2 du code de la sécurité sociale est remplacé par les dispositions suivantes :",
  "« Art. D. 911-2.-Sans préjudice des dispositions du deuxième alinéa du III de l'article L. 911-7, peuvent se dispenser, à leur initiative, de l'obligation d'adhésion à la couverture en matière de remboursement complémentaire de frais occasionnés par une maladie, une maternité ou un accident mise en place dans leur entreprise :",
  "« 1° Les salariés bénéficiaires d'une couverture complémentaire en application de l'article L. 861-3 ou d'une aide à l'acquisition d'une complémentaire santé en application de l'article L. 863-1. La dispense ne peut jouer que jusqu'à la date à laquelle les salariés cessent de bénéficier de cette couverture ou de cette aide ;",
  "« 2° Les salariés couverts par une assurance individuelle de frais de santé au moment de la mise en place des garanties ou de l'embauche si elle est postérieure. La dispense ne peut jouer que jusqu'à échéance du contrat individuel ;",
  "« 3° Les salariés qui bénéficient, pour les mêmes risques, y compris en tant qu'ayants droit, de prestations servies au titre d'un autre emploi en tant que bénéficiaire de l'un ou l'autre des dispositifs suivants :",
  "« a) Dispositif de garanties remplissant les conditions mentionnées au sixième alinéa de l'article L. 242-1 ;",
  "« b) Dispositif de garanties prévu par le décret n° 2007-1373 du 19 septembre 2007 relatif à la participation de l'Etat et de ses établissements publics au financement de la protection sociale complémentaire de leurs personnels ou par le décret n° 2011-1474 du 8 novembre 2011 relatif à la participation des collectivités territoriales et de leurs établissements publics au financement de la protection sociale complémentaire de leurs agents ;",
  "« c) Contrats d'assurance de groupe issus de la loi n° 94-126 du 11 février 1994 relative à l'initiative et à l'entreprise individuelle ;",
  "« d) Régime local d'assurance maladie du Haut-Rhin, du Bas-Rhin et de la Moselle, en application des articles D. 325-6 et D. 325-7 du code de la sécurité sociale ;",
  "« e) Régime complémentaire d'assurance maladie des industries électriques et gazières en application du décret n° 46-1541 du 22 juin 1946.",
  "« Dans tous les cas, l'employeur doit être en mesure de produire la demande de dispense des salariés concernés. »",
].join("\n");

export function renderAttestationMutuellePdf(data: AttestationMutuellePdfData) {
  return toBuffer((document) => {
    const titleMargin = 72;
    const titleWidth = document.page.width - titleMargin * 2;
    document
      .lineWidth(0.75)
      .rect(titleMargin, 35, titleWidth, 24)
      .stroke("#111111");
    document
      .font("DocumentBold")
      .fontSize(15)
      .text("ATTESTATION", titleMargin, 39, {
        width: titleWidth,
        align: "center",
      });
    const margin = 76;
    const width = document.page.width - margin * 2;
    document
      .font("DocumentRegular")
      .fontSize(9.2)
      .text(
        `Je ${data.formuleSoussignataire}, ${data.signataireNom} - ${data.signataireFonction} de la ${data.entreprise}, atteste par la présente que ${employmentSentence(data)}`,
        margin,
        83,
        { width, align: "justify", lineGap: 1.2 },
      );
    const echeance = data.dateEcheanceMutuelle
      ? ` À l'échéance de ce dernier, le ${formatLongFrenchDate(data.dateEcheanceMutuelle)},`
      : " À la date d'échéance de ce dernier,";
    document.text(
      `${data.titreNomPrenom} a déjà bénéficié d'une dérogation à la souscription de la mutuelle de l'entreprise puisqu'il disposait déjà d'un contrat à titre personnel.${echeance} il se voit dans l'obligation d'adhérer à notre partenaire prévoyance.`,
      margin,
      document.y + 16,
      { width, align: "justify", lineGap: 1.2 },
    );
    document
      .fontSize(7.4)
      .text(MUTUELLE_LEGAL_TEXT, margin, document.y + 10, {
        width,
        align: "justify",
        lineGap: 0.55,
      });
    document
      .fontSize(9.5)
      .text("Pour faire et valoir ce que de droit.", 108, document.y + 12);
    drawSignature(document, data, 724);
  }, `Attestation mutuelle - ${data.titreNomPrenom}`);
}

export function renderAttestationProlongationMutuellePdf(
  data: AttestationProlongationMutuellePdfData,
) {
  return toBuffer((document) => {
    drawAttestationTitle(document);
    const margin = 76;
    const width = document.page.width - margin * 2;
    document
      .font("DocumentRegular")
      .fontSize(11.5)
      .text(
        `Je ${data.formuleSoussignataire}, ${data.signataireNom} - ${data.signataireFonction} de la ${data.entreprise}, atteste par la présente que ${data.titreNomPrenom} ${data.domicilie} ${data.adresseLigne} a travaillé du ${formatLongFrenchDate(data.dateEmbauche)} au ${formatLongFrenchDate(data.dateSortiePrevue)} au sein de notre société en ${data.typeContrat}. Il sera repris en contrat à durée déterminée le ${formatLongFrenchDate(data.dateReprise)}.`,
        margin,
        314,
        { width, align: "justify", lineGap: 2.5 },
      );
    document.text(
      "Je vous demande donc de bien vouloir prolonger son contrat mutuelle jusqu'à sa sortie définitive.",
      margin,
      document.y + 28,
      { width, align: "justify", lineGap: 2.5 },
    );
    document.text("Pour faire et valoir ce que de droit.", 108, document.y + 52);
    drawSignature(document, data);
  }, `Attestation de prolongation mutuelle - ${data.titreNomPrenom}`);
}

function section(document: Pdf, title: string, y: number) {
  document.rect(86, y, 424, 19).fillAndStroke("#dddddd", "#111111");
  document
    .font("DocumentBold")
    .fontSize(10.5)
    .fillColor("#111111")
    .text(title, 91, y + 4, { width: 414 });
}

function line(document: Pdf, label: string, value: string, y: number) {
  const valueOptions = { width: 290, lineGap: 1 } as const;
  const valueHeight = document
    .font("DocumentRegular")
    .fontSize(8.7)
    .heightOfString(value || "", valueOptions);

  document
    .font("DocumentRegular")
    .fontSize(8.7)
    .text(label, 91, y, { width: 120 })
    .text(value || "", 211, y, valueOptions);

  return y + Math.max(17, valueHeight + 2);
}

export function renderAutorisationPrefecturePdf(
  data: AutorisationPrefecturePdfData,
) {
  return toBuffer((document) => {
    document
      .font("DocumentBold")
      .fontSize(12)
      .text("PREFECTURE DU NORD", 72, 22, { width: 451, align: "center" })
      .fontSize(11)
      .text(
        "DEMANDE DE VERIFICATION PREALABLE DU TITRE DE SEJOUR ET/OU DE L'AUTORISATION DE TRAVAIL",
        72,
        58,
        { width: 451, align: "center" },
      );

    let y = 105;
    section(document, "SOCIETE :", y);
    y += 32;
    y = line(document, "Entreprise :", data.entreprise, y);
    y = line(document, "Adresse :", data.adresseEntreprise, y) + 9;
    y =
      line(
        document,
        "Correspondant :",
        `${data.correspondantNom} - ${data.correspondantFonction}`,
        y,
      ) + 14;
    y = line(document, "Tél. :", data.telephoneEntreprise, y) + 7;
    y = line(document, "N° SIRET :", data.siret, y);
    y = line(document, "N° URSSAF :", data.urssaf, y) + 13;

    section(document, "SALARIE(E) :", y);
    y += 32;
    y = line(document, "NOM - Prénom :", data.nomPrenom, y);
    y = line(document, "Adresse :", data.adresseSalarie, y) + 7;
    y = line(document, "Né(e) le :", formatLongFrenchDate(data.dateNaissance), y);
    y = line(document, "Pays de naissance :", data.paysNaissance, y);
    y = line(document, "Nationalité :", data.nationalite, y);
    y =
      line(document, "N° Sécurité sociale :", data.numeroSecuriteSociale, y) +
      12;
    y = line(document, "Titre de séjour :", data.titreSejour, y);
    y = line(document, "Motif du séjour :", data.motifSejour, y) + 12;
    y = line(document, "N° carte de séjour :", data.numeroCarteSejour, y);
    y = line(document, "Délivrée le :", formatLongFrenchDate(data.dateDelivrance), y);
    y =
      line(document, "Expire le :", formatLongFrenchDate(data.dateExpiration), y) +
      16;

    section(document, "CONTRAT DE TRAVAIL :", y);
    y += 32;
    y = line(
      document,
      "Début du contrat :",
      formatLongFrenchDate(data.dateDebutContrat),
      y,
    );
    y = line(document, "Durée du contrat :", data.dureeContrat, y);
    y = line(document, "Type de contrat :", data.typeContrat, y);
    y = line(document, "Fonction :", data.poste, y) + 15;
    y = line(document, "Heures hebdomadaires :", data.heuresHebdomadaires, y);
    y = line(document, "Pièce jointe :", "copie du titre produit", y);

    document
      .font("DocumentRegular")
      .fontSize(9.5)
      .text(
        `Fait à ${data.lieuDocument}, le ${formatLongFrenchDate(data.dateDocument)}`,
        300,
        Math.max(724, y + 27),
        { width: 210, align: "right" },
      );
  }, `Autorisation préfecture - ${data.nomPrenom}`);
}