import { prisma } from "@/lib/prisma";

const INCLUDED_SECTOR_IDS = [
  1, 2, 3, 5, 6, 7, 8, 9, 10, 11,
] as const;

const SECTOR_LABEL_ALIASES: Record<string, string> = {
  tes: "Logistique Adm",
};

function normalizeSector(value: string | null | undefined) {
  return (value ?? "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/\s+/g, " ")
    .trim()
    .toLocaleLowerCase("fr");
}

function displaySector(value: string | null | undefined) {
  const normalized = normalizeSector(value);

  return SECTOR_LABEL_ALIASES[normalized] ?? value?.trim() ?? "";
}

export type SalarieImpression = {
  cos: number;
  nom: string;
  prenom: string;
};

export type SecteurImpression = {
  id: number;
  secteur: string;
  salaries: SalarieImpression[];
};

export type SalariesEnCoursReport = {
  generatedAt: Date;
  secteurs: SecteurImpression[];
  totalSalaries: number;
  salariesSansSecteur: number;
};

export async function getSalariesEnCoursReport(): Promise<SalariesEnCoursReport> {
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  const [secteursReference, contratsActifs] = await Promise.all([
    prisma.secteurs_travail.findMany({
      where: {
        id: {
          in: [...INCLUDED_SECTOR_IDS],
        },
      },
      orderBy: {
        id: "asc",
      },
      select: {
        id: true,
        secteurs: true,
      },
    }),
    prisma.contrats.findMany({
      where: {
        Id_Salarie: {
          not: null,
        },
        OR: [
          {
            DAE: null,
          },
          {
            DAE: {
              lte: today,
            },
          },
        ],
      },
      orderBy: [
        {
          DAE: "desc",
        },
        {
          id: "desc",
        },
      ],
      select: {
        id: true,
        Id_Salarie: true,
        ETB: true,
        Secteur: true,
        DSR: true,
        employes: {
          select: {
            COS: true,
            NSA: true,
            PRE: true,
          },
        },
      },
    }),
  ]);

  const secteurs: SecteurImpression[] = secteursReference.map((item) => ({
    id: item.id,
    secteur: displaySector(item.secteurs),
    salaries: [],
  }));

  const secteursByName = new Map(
    secteurs.map((item) => [normalizeSector(item.secteur), item]),
  );

  const logistiqueAdm = secteurs.find(
    (item) => normalizeSector(item.secteur) === "logistique adm",
  );

  if (logistiqueAdm) {
    secteursByName.set("tes", logistiqueAdm);
  }

  const salariesDejaAffectes = new Set<number>();
  let salariesSansSecteur = 0;

  for (const contrat of contratsActifs) {
    const employe = contrat.employes;
    const cos = employe?.COS ?? contrat.Id_Salarie;

    if (!cos || salariesDejaAffectes.has(cos)) {
      continue;
    }

    salariesDejaAffectes.add(cos);

    const etablissement =
      contrat.ETB?.trim().toLocaleUpperCase("fr") ?? "";

    if (
      contrat.DSR != null ||
      !["LESQUIN", "ENVIE LESQUIN"].includes(etablissement)
    ) {
      continue;
    }

    const secteur = secteursByName.get(normalizeSector(contrat.Secteur));

    if (!secteur) {
      salariesSansSecteur += 1;
      continue;
    }

    secteur.salaries.push({
      cos,
      nom: employe?.NSA?.trim() ?? "",
      prenom: employe?.PRE?.trim() ?? "",
    });
  }

  for (const secteur of secteurs) {
    secteur.salaries.sort(
      (left, right) =>
        left.nom.localeCompare(right.nom, "fr", { sensitivity: "base" }) ||
        left.prenom.localeCompare(right.prenom, "fr", {
          sensitivity: "base",
        }),
    );
  }

  return {
    generatedAt: new Date(),
    secteurs,
    totalSalaries: secteurs.reduce(
      (total, secteur) => total + secteur.salaries.length,
      0,
    ),
    salariesSansSecteur,
  };
}