import {
  computeSallePricing,
  type SalleReservationFrequency,
  type SalleUsageType,
} from "@shared/sallePricing";

export const sallesMJS = [
  {
    id: "bureau_11_17",
    nom: "Bureau 11–17 m²",
    description: "Bureau pour usage administratif ou ponctuel",
    capacite: "Espace bureau",
    icon: "🗂️",
  },
  {
    id: "salle_toucan",
    nom: "Salle TOUCAN",
    description: "Salle polyvalente",
    capacite: "Grande capacité",
    icon: "🦜",
  },
  {
    id: "salle_ibis",
    nom: "Salle IBIS",
    description: "Salle de réunion",
    capacite: "Capacité moyenne",
    icon: "🦩",
  },
  {
    id: "salle_pelican",
    nom: "Salle PELICAN",
    description: "Salle polyvalente",
    capacite: "Grande capacité",
    icon: "🐦",
  },
  {
    id: "dojo",
    nom: "DOJO",
    description: "Salle d'arts martiaux et activités sportives",
    capacite: "Capacité moyenne",
    icon: "🥋",
  },
  {
    id: "hall_amphitheatre",
    nom: "Hall-Amphithéâtre",
    description: "Grand espace pour événements et conférences",
    capacite: "Grande capacité",
    icon: "🎭",
  },
  {
    id: "vestiaires",
    nom: "Vestiaires",
    description: "Vestiaires pour activités sportives",
    capacite: "Annexe",
    icon: "🚿",
  },
] as const;

export type ReservationSalleFormData = {
  motifReservation: string;
  dateReservation: string;
  dateFinReservation: string;
  heureDebut: string;
  heureFin: string;
  useDetailedSchedule: boolean;
  horairesParJour: ReservationSalleDailySlot[];
  typeUsage: SalleUsageType;
  frequence: SalleReservationFrequency;
  nombreParticipants: string;
  besoinsComplementaires: string;
  materielNecessaire: string;
  observations: string;
};

export type ReservationSalleDailySlot = {
  date: string;
  heureDebut: string;
  heureFin: string;
};

type AssociationProfileLike = {
  nomAssociation?: string | null;
  adresse?: string | null;
  codePostal?: string | null;
  ville?: string | null;
  nomRepresentant?: string | null;
  telephone?: string | null;
  emailContact?: string | null;
};

type ReservationSallePayloadOptions = {
  existingData?: Record<string, any>;
  association?: AssociationProfileLike | null;
  formData: ReservationSalleFormData;
  selectedSalles: string[];
};

export const emptyReservationSalleFormData = (): ReservationSalleFormData => ({
  motifReservation: "",
  dateReservation: "",
  dateFinReservation: "",
  heureDebut: "",
  heureFin: "",
  useDetailedSchedule: false,
  horairesParJour: [],
  typeUsage: "conventionne",
  frequence: "journee",
  nombreParticipants: "",
  besoinsComplementaires: "",
  materielNecessaire: "",
  observations: "",
});

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

function toDateString(parts: { year: number; month: number; day: number }) {
  const month = String(parts.month).padStart(2, "0");
  const day = String(parts.day).padStart(2, "0");
  return `${parts.year}-${month}-${day}`;
}

export function listReservationDates(start: string, end: string): string[] {
  const startParts = parseDateParts(start);
  const endParts = parseDateParts(end);
  if (!startParts || !endParts) return [];

  const dates: string[] = [];
  const cursor = new Date(Date.UTC(startParts.year, startParts.month - 1, startParts.day));
  const endDate = new Date(Date.UTC(endParts.year, endParts.month - 1, endParts.day));

  while (cursor.getTime() <= endDate.getTime()) {
    dates.push(
      toDateString({
        year: cursor.getUTCFullYear(),
        month: cursor.getUTCMonth() + 1,
        day: cursor.getUTCDate(),
      })
    );
    cursor.setUTCDate(cursor.getUTCDate() + 1);
  }

  return dates;
}

export function syncReservationSalleDailySlots(
  start: string,
  end: string,
  existingSlots: ReservationSalleDailySlot[],
  defaultStart = "",
  defaultEnd = ""
): ReservationSalleDailySlot[] {
  const dates = listReservationDates(start, end);
  const existingMap = new Map(existingSlots.map((slot) => [slot.date, slot]));

  return dates.map((date) => ({
    date,
    heureDebut: existingMap.get(date)?.heureDebut || defaultStart,
    heureFin: existingMap.get(date)?.heureFin || defaultEnd,
  }));
}

function normalizeSalleLabel(value: string) {
  return value
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, " ")
    .trim();
}

function deriveSalleIdsFromNames(names: string[]): string[] {
  const normalizedNames = names.map(normalizeSalleLabel);
  return sallesMJS
    .filter((salle) => normalizedNames.includes(normalizeSalleLabel(salle.nom)))
    .map((salle) => salle.id);
}

function deriveSalleIdsFromTitle(title?: string): string[] {
  if (!title?.startsWith("Réservation ")) {
    return [];
  }

  const namesPart = title.replace(/^Réservation\s+/, "").split(" - ")[0] || "";
  const names = namesPart
    .split(",")
    .map((value) => value.trim())
    .filter(Boolean);

  return deriveSalleIdsFromNames(names);
}

export function parseReservationSallePayload(rawFormData?: string | null): {
  originalData: Record<string, any>;
  formData: ReservationSalleFormData;
  selectedSalles: string[];
} & { legacyDetected: boolean } {
  let parsed: Record<string, any> = {};

  try {
    parsed = rawFormData ? JSON.parse(rawFormData) : {};
  } catch {
    parsed = {};
  }

  const selectedSalles = Array.isArray(parsed.sallesIds)
    ? parsed.sallesIds.filter((value: unknown): value is string => typeof value === "string" && value.trim().length > 0)
    : Array.isArray(parsed.sallesSelectionnees)
      ? deriveSalleIdsFromNames(parsed.sallesSelectionnees.filter((value: unknown): value is string => typeof value === "string"))
      : deriveSalleIdsFromTitle(String(parsed.titre || parsed.description || ""));

  const legacyDateSouhaitee = String(parsed.dateSouhaitee || "");
  const legacyHeureDebut = String(parsed["heureDébut"] || "");
  const legacyHeureFin = String(parsed["heureFin"] || "");
  const rawSlots = Array.isArray(parsed.horairesParJour) ? parsed.horairesParJour : [];
  const horairesParJour = rawSlots
    .map((slot) => ({
      date: String(slot?.date || ""),
      heureDebut: String(slot?.heureDebut || ""),
      heureFin: String(slot?.heureFin || ""),
    }))
    .filter((slot) => slot.date);
  const useDetailedSchedule = Boolean(parsed.useDetailedSchedule || horairesParJour.length > 0);

  const legacyDetected = Boolean(legacyDateSouhaitee || legacyHeureDebut || legacyHeureFin);
  const dateReservation = String(parsed.dateReservation || legacyDateSouhaitee || parsed.dateDebut || "");
  const dateFinReservation = String(
    parsed.dateFinReservation
      || parsed.dateFin
      || legacyDateSouhaitee
      || parsed.dateReservation
      || ""
  );
  const heureDebut = String(parsed.heureDebut || legacyHeureDebut || "");
  const heureFin = String(parsed.heureFin || legacyHeureFin || "");

  return {
    originalData: parsed,
    selectedSalles,
    legacyDetected,
    formData: {
      motifReservation: String(parsed.motifReservation || parsed.description || ""),
      dateReservation,
      dateFinReservation,
      heureDebut,
      heureFin,
      useDetailedSchedule,
      horairesParJour: useDetailedSchedule
        ? syncReservationSalleDailySlots(dateReservation, dateFinReservation, horairesParJour, heureDebut, heureFin)
        : [],
      nombreParticipants: String(parsed.nombreParticipants || ""),
      typeUsage: parsed.typeUsage === "occasionnel" ? "occasionnel" : "conventionne",
      frequence: parsed.frequence === "demi_journee" || parsed.frequence === "mensuel" ? parsed.frequence : "journee",
      besoinsComplementaires: String(parsed.besoinsComplementaires || ""),
      materielNecessaire: String(parsed.materielNecessaire || ""),
      observations: String(parsed.observations || ""),
    },
  };
}

export function buildReservationSalleTitle(selectedSalles: string[], dateReservation: string): string {
  const sallesNoms = selectedSalles.map((id) => sallesMJS.find((salle) => salle.id === id)?.nom || id);
  const dateLabel = dateReservation
    ? new Date(dateReservation).toLocaleDateString("fr-FR")
    : "sans date";
  return `Réservation ${sallesNoms.join(", ")} - ${dateLabel}`;
}

export function validateReservationSalleFormInput(
  formData: ReservationSalleFormData,
  selectedSalles: string[]
): string | null {
  if (selectedSalles.length === 0) {
    return "Veuillez sélectionner au moins une salle";
  }

  if (!formData.motifReservation.trim()) {
    return "Veuillez indiquer le motif de la réservation";
  }

  if (!formData.dateReservation) {
    return "Veuillez indiquer la date de début de la réservation";
  }

  if (!formData.dateFinReservation) {
    return "Veuillez indiquer la date de fin de la réservation";
  }

  if (formData.dateFinReservation < formData.dateReservation) {
    return "La date de fin doit être postérieure ou égale à la date de début";
  }

  if (formData.useDetailedSchedule) {
    if (formData.horairesParJour.length === 0) {
      return "Veuillez renseigner au moins un créneau détaillé";
    }

    const validDates = new Set(listReservationDates(formData.dateReservation, formData.dateFinReservation));
    for (const slot of formData.horairesParJour) {
      if (!validDates.has(slot.date)) {
        return "Un créneau détaillé ne correspond pas à la période sélectionnée";
      }
      if (!slot.heureDebut || !slot.heureFin) {
        return "Veuillez renseigner les horaires de chaque journée";
      }
      if (slot.heureFin <= slot.heureDebut) {
        return "Chaque créneau détaillé doit avoir une heure de fin postérieure à l'heure de début";
      }
    }
  } else {
    if (!formData.heureDebut) {
      return "Veuillez indiquer l'heure de début";
    }

    if (!formData.heureFin) {
      return "Veuillez indiquer l'heure de fin";
    }

    if (formData.heureFin <= formData.heureDebut) {
      return "L'heure de fin doit être postérieure à l'heure de début";
    }
  }

  if (!formData.nombreParticipants) {
    return "Veuillez indiquer le nombre de participants";
  }

  const pricing = computeSallePricing({
    sallesIds: selectedSalles,
    usageType: formData.typeUsage,
    frequency: formData.frequence,
    dateReservation: formData.dateReservation,
    dateFinReservation: formData.dateFinReservation,
  });

  if (pricing.unsupportedSalles.length > 0) {
    return `Aucune tarification automatique n'est disponible pour : ${pricing.unsupportedSalles.map((item) => item.salleNom).join(", ")} avec ce type d'usage et cette fréquence`;
  }

  return null;
}

export function buildReservationSallePayload({
  existingData = {},
  association,
  formData,
  selectedSalles,
}: ReservationSallePayloadOptions) {
  const sallesSelectionnees = selectedSalles.map((id) => sallesMJS.find((salle) => salle.id === id)?.nom || id);

  return {
    ...existingData,
    nomAssociation: association?.nomAssociation || existingData.nomAssociation || "",
    adresseAssociation: association?.adresse
      ? `${association.adresse}, ${association.codePostal || ""} ${association.ville || ""}`.trim()
      : existingData.adresseAssociation || "",
    communeSiege: association?.ville || existingData.communeSiege || "",
    representantLegal: association?.nomRepresentant || existingData.representantLegal || "",
    telephoneAssociation: association?.telephone || existingData.telephoneAssociation || "",
    emailAssociation: association?.emailContact || existingData.emailAssociation || "",
    sallesSelectionnees,
    sallesIds: selectedSalles,
    motifReservation: formData.motifReservation,
    dateReservation: formData.dateReservation,
    dateFinReservation: formData.dateFinReservation,
    heureDebut: formData.heureDebut,
    heureFin: formData.heureFin,
    useDetailedSchedule: formData.useDetailedSchedule,
    horairesParJour: formData.useDetailedSchedule ? formData.horairesParJour : [],
    typeUsage: formData.typeUsage,
    frequence: formData.frequence,
    nombreParticipants: formData.nombreParticipants,
    besoinsComplementaires: formData.besoinsComplementaires,
    materielNecessaire: formData.materielNecessaire,
    observations: formData.observations,
    formulaireType: "reservation_salle_mjs",
    destinataire: "Direction des Services aux Usagers (DSU)",
    emailDestinataire: "mjs@ccds-guyane.fr",
    lieu: "Maison de la Jeunesse des Savanes",
  };
}

export function formatReservationSallePeriod(formData: Pick<ReservationSalleFormData, "dateReservation" | "dateFinReservation">) {
  const formatReservationSalleDate = (date: string) => {
    if (!date) return "-";

    try {
      return new Date(date).toLocaleDateString("fr-FR", {
        day: "numeric",
        month: "long",
        year: "numeric",
      });
    } catch {
      return date;
    }
  };

  if (!formData.dateReservation) return "-";
  if (!formData.dateFinReservation || formData.dateFinReservation === formData.dateReservation) {
    return formatReservationSalleDate(formData.dateReservation);
  }
  return `${formatReservationSalleDate(formData.dateReservation)} au ${formatReservationSalleDate(formData.dateFinReservation)}`;
}

export function getReservationSalleScheduleSummary(formData: Pick<ReservationSalleFormData, "useDetailedSchedule" | "horairesParJour" | "heureDebut" | "heureFin">) {
  if (formData.useDetailedSchedule && formData.horairesParJour.length > 0) {
    return `Horaires détaillés sur ${formData.horairesParJour.length} jour(s)`;
  }

  if (formData.heureDebut || formData.heureFin) {
    return `${formData.heureDebut || "?"} — ${formData.heureFin || "?"}`;
  }

  return "-";
}
