﻿import { prisma } from "@/lib/prisma";
import type { Prisma } from "@/generated/prisma/client";
import { hasContratForSalarie } from "@/services/contrats.service";
import type {
  EmployeCreateInput,
  EmployeUpdateInput,
} from "@/validators/employes";

export type EmployeeAccessScope = {
  sectors: string[] | undefined;
  establishments: string[] | undefined;
  categories: string[] | undefined;
  contractTypes: string[] | undefined;
};

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

function isValueAllowed(
  value: string | null | undefined,
  allowedValues: string[] | undefined,
) {
  if (allowedValues === undefined) return true;

  const normalizedValue = normalizeScopeValue(value);
  return allowedValues.some(
    (allowed) => normalizeScopeValue(allowed) === normalizedValue,
  );
}

type ScopedContract = {
  Secteur: string | null;
  ETB: string | null;
  CAT: string | null;
  TCS: string | null;
};

function isContractAllowed(
  contract: ScopedContract | undefined,
  scope: EmployeeAccessScope,
) {
  return (
    isValueAllowed(contract?.Secteur, scope.sectors) &&
    isValueAllowed(contract?.ETB, scope.establishments) &&
    isValueAllowed(contract?.CAT, scope.categories) &&
    isValueAllowed(contract?.TCS, scope.contractTypes)
  );
}

export async function listEmployes(
  limit: number,
  offset: number,
  scope: EmployeeAccessScope,
) {
  const employes = await prisma.employes.findMany({
    orderBy: [{ NSA: "asc" }, { PRE: "asc" }],
    select: {
      id: true,
      COS: true,
      TIT: true,
      NSA: true,
      NJF: true,
      PRE: true,
      VIL: true,
      EmailE2e: true,
      Actif: true,

      contrats: {
        where: {
          OR: [{ DAE: null }, { DAE: { lte: new Date() } }],
        },
        orderBy: [{ DAE: "desc" }, { id: "desc" }],
        select: {
          id: true,
          DAE: true,
          DSP: true,
          DSR: true,
          ETB: true,
          Secteur: true,
          CAT: true,
          TCS: true,
        },
      },
    },
  });

   const today = new Date();
  today.setHours(0, 0, 0, 0);
  return employes
    .map((e) => {
      const dernierContratCommence = e.contrats[0];
  
     
const actifSelonContrats =
  dernierContratCommence != null &&
  dernierContratCommence.DSR == null &&
  (dernierContratCommence.DSP == null ||
    dernierContratCommence.DSP >= today);

      return {
        ...e,
        Actif: actifSelonContrats,
      };
    })
    .filter((employe) => isContractAllowed(employe.contrats[0], scope))
    .slice(offset, offset + limit);
}

export async function getEmployeByCos(
  cos: number,
  scope?: EmployeeAccessScope,
) {
  const employe = await prisma.employes.findUnique({
    where: {
      COS: cos,
    },
  });

  if (!employe || scope === undefined) return employe;

  const lastStartedContract = await prisma.contrats.findFirst({
    where: {
      Id_Salarie: cos,
      OR: [{ DAE: null }, { DAE: { lte: new Date() } }],
    },
    orderBy: [{ DAE: "desc" }, { id: "desc" }],
    select: {
      Secteur: true,
      ETB: true,
      CAT: true,
      TCS: true,
    },
  });

  return isContractAllowed(lastStartedContract ?? undefined, scope)
    ? employe
    : null;
}

export async function createEmploye(data: EmployeCreateInput) {
  return prisma.$transaction(async (tx) => {
    const counter = await tx.system_counters.update({
      where: {
        name: "employee_cos",
      },
      data: {
        value: {
          increment: 1,
        },
      },
      select: {
        value: true,
      },
    });

    return tx.employes.create({
      data: {
        ...data,
        COS: counter.value,
      } as Prisma.employesCreateInput,
    });
  });
}

export async function updateEmployeByCos(
  cos: number,
  data: EmployeUpdateInput,
) {
  const existing = await prisma.employes.findUnique({
    where: {
      COS: cos,
    },
  });

  if (!existing) {
    return null;
  }

  return prisma.employes.update({
    where: {
      COS: cos,
    },
    data: data as Prisma.employesUpdateInput,
  });
}

export async function deleteEmployeByCos(cos: number) {
  const existing = await prisma.employes.findUnique({
    where: {
      COS: cos,
    },
  });

  if (!existing) {
    return null;
  }

  if (await hasContratForSalarie(cos)) {
    const error = new Error(
      "Cannot delete employe with dependent contrats",
    ) as Error & {
      code?: string;
    };

    error.code = "P2003";
    throw error;
  }

  return prisma.employes.delete({
    where: {
      COS: cos,
    },
  });
}
