import { type ClassValue, clsx } from "clsx";
import { del } from "idb-keyval";
import { DateTime } from "luxon";
import type { NavigateFunction } from "react-router";
import { twMerge } from "tailwind-merge";
import { CACHE_KEY } from "./client";
import type { User, UserPreferences } from "./api";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

/**
 * === STRING UTILS ===
 */
export function capitalizeFirstLetter(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

export function titleCase(str: string) {
  return str.replace(
    /\w\S*/g,
    (text) => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase()
  );
}

/**
 * === NAVIGATION UTILS ===
 */
// Force a reload of the page
export function forceReload() {
  window.location.reload();
}

export function goBack(navigate: NavigateFunction) {
  let canGoBack = false;
  // Check if there is a history stack to go back to
  try {
    canGoBack = window.history.length > 1;
  } catch (e) {
    canGoBack = false;
  }
  if (!canGoBack) {
    return navigate("/");
  } else {
    return navigate(-1);
  }
}

/**
 * === COLLES UTILS ===
 */
export const formatDate = (date: string) => {
  const dt = DateTime.fromISO(date).setLocale("fr");
  const str = dt.toLocaleString({
    weekday: "long",
    day: "numeric",
    month: "long",
    year: "numeric",
  });
  return titleCase(str);
};

export const formatTime = (date: string) => {
  const dt = DateTime.fromISO(date).setLocale("fr");
  return (
    dt
      .toLocaleString({
        hour: "2-digit",
        minute: "2-digit",
      })
      ?.replace(":", "h") || "N/A"
  );
};

export const formatGrade = (grade?: number) => {
  if (grade === undefined || grade === null || grade < 0 || grade > 20)
    return "N/A";

  const rounded = Math.round(grade * 10) / 10;
  const str =
    rounded % 1 === 0
      ? rounded.toFixed(0) // no decimals if .0
      : rounded.toFixed(1); // one decimal otherwise

  return str.replace(".", ",").padStart(2, "0"); // pad with zero if needed
};

// === COLORS UTILS ===
export const colors = [
  "red",
  "orange",
  "amber",
  "yellow",
  "lime",
  "green",
  "emerald",
  "teal",
  "cyan",
  "sky",
  "blue",
  "indigo",
  "violet",
  "purple",
  "fuchsia",
  "pink",
  "rose",
  "slate",
  "zinc",
];

export const getColorClass = (colorCode: string) =>
  `bg-${colorCode}-100 text-${colorCode}-800 dark:bg-${colorCode}-300 dark:text-${colorCode}-900 hover:bg-${colorCode}-100 dark:hover:bg-${colorCode}-300`;

// Used for Tailwind CSS to generate the classes
export const classNames = [
  [
    "bg-red-100 text-red-800 dark:bg-red-300 dark:text-red-900 hover:bg-red-100 dark:hover:bg-red-300",
    "bg-orange-100 text-orange-800 dark:bg-orange-300 dark:text-orange-900 hover:bg-orange-100 dark:hover:bg-orange-300",
    "bg-amber-100 text-amber-800 dark:bg-amber-300 dark:text-amber-900 hover:bg-amber-100 dark:hover:bg-amber-300",
    "bg-yellow-100 text-yellow-800 dark:bg-yellow-300 dark:text-yellow-900 hover:bg-yellow-100 dark:hover:bg-yellow-300",
    "bg-lime-100 text-lime-800 dark:bg-lime-300 dark:text-lime-900 hover:bg-lime-100 dark:hover:bg-lime-300",
    "bg-green-100 text-green-800 dark:bg-green-300 dark:text-green-900 hover:bg-green-100 dark:hover:bg-green-300",
    "bg-emerald-100 text-emerald-800 dark:bg-emerald-300 dark:text-emerald-900 hover:bg-emerald-100 dark:hover:bg-emerald-300",
    "bg-teal-100 text-teal-800 dark:bg-teal-300 dark:text-teal-900 hover:bg-teal-100 dark:hover:bg-teal-300",
    "bg-cyan-100 text-cyan-800 dark:bg-cyan-300 dark:text-cyan-900 hover:bg-cyan-100 dark:hover:bg-cyan-300",
    "bg-sky-100 text-sky-800 dark:bg-sky-300 dark:text-sky-900 hover:bg-sky-100 dark:hover:bg-sky-300",
    "bg-blue-100 text-blue-800 dark:bg-blue-300 dark:text-blue-900 hover:bg-blue-100 dark:hover:bg-blue-300",
    "bg-indigo-100 text-indigo-800 dark:bg-indigo-300 dark:text-indigo-900 hover:bg-indigo-100 dark:hover:bg-indigo-300",
    "bg-violet-100 text-violet-800 dark:bg-violet-300 dark:text-violet-900 hover:bg-violet-100 dark:hover:bg-violet-300",
    "bg-purple-100 text-purple-800 dark:bg-purple-300 dark:text-purple-900 hover:bg-purple-100 dark:hover:bg-purple-300",
    "bg-fuchsia-100 text-fuchsia-800 dark:bg-fuchsia-300 dark:text-fuchsia-900 hover:bg-fuchsia-100 dark:hover:bg-fuchsia-300",
    "bg-pink-100 text-pink-800 dark:bg-pink-300 dark:text-pink-900 hover:bg-pink-100 dark:hover:bg-pink-300",
    "bg-rose-100 text-rose-800 dark:bg-rose-300 dark:text-rose-900 hover:bg-rose-100 dark:hover:bg-rose-300",
    "bg-slate-100 text-slate-800 dark:bg-slate-300 dark:text-slate-900 hover:bg-slate-100 dark:hover:bg-slate-300",
    "bg-zinc-100 text-zinc-800 dark:bg-zinc-300 dark:text-zinc-900 hover:bg-zinc-100 dark:hover:bg-zinc-300",
    "bg-gray-100 text-gray-800 dark:bg-gray-300 dark:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-300",
  ],
];

export const DEFAULT_COLOR = "blue"; // Default color for subjects
export const DEFAULT_EMOJI = "📚"; // Default emoji for subjects

export const getSubjectEmoji = (subject: string, pref: UserPreferences) => {
  const preference = pref.find((p) => p.name === subject);
  return preference ? preference.emoji : DEFAULT_EMOJI;
};
export const getSubjectColor = (subject: string, pref: UserPreferences) => {
  const preference = pref.find((p) => p.name === subject);
  return preference ? preference.color : DEFAULT_COLOR;
};

// === DEBUG UTILS ===
export const clearCache = () => del(CACHE_KEY);

// === MP* COLLES SYLLABUS CONSTANTS ===
export function getColleWeek(date: Date) {
  // Define week ranges [start, end, week_number]
  const weeks = [
    ["15/09/2025", "20/09/2025", 0],
    ["22/09/2025", "27/09/2025", 1],
    ["29/09/2025", "04/10/2025", 2],
    ["06/10/2025", "11/10/2025", 3],
    ["13/10/2025", "18/10/2025", 4],
    ["03/11/2025", "08/11/2025", 5],
    ["10/11/2025", "15/11/2025", 6],
    ["17/11/2025", "22/11/2025", 7],
    ["24/11/2025", "29/11/2025", 8],
    ["01/12/2025", "06/12/2025", 9],
    ["08/12/2025", "13/12/2025", 10],
    ["15/12/2025", "20/12/2025", 11],
    ["05/01/2026", "10/01/2026", 12],
    ["12/01/2026", "17/01/2026", 13],
    ["19/01/2026", "24/01/2026", 14],
    ["26/01/2026", "31/01/2026", 15],
    ["02/02/2026", "07/02/2026", 16],
    ["09/02/2026", "14/02/2026", 17],
    ["09/03/2026", "14/03/2026", 18],
    ["16/03/2026", "21/03/2026", 19],
  ] as [string, string, number][];

  // Helper function to parse DD/MM/YYYY string to Date
  function parseDate(dateStr: string): Date {
    const [day, month, year] = dateStr.split("/").map(Number);
    return new Date(year, month - 1, day);
  }

  // Check which week the date falls into
  for (const [startStr, endStr, weekNum] of weeks) {
    const startDate = parseDate(startStr);
    const endDate = parseDate(endStr);

    if (date >= startDate && date <= endDate) {
      return weekNum;
    }
  }

  return null;
}
