"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useCurrentUser } from "../user-context";

interface CalEvent {
  id: string;
  summary: string;
  start: string | null;
  end: string | null;
  allDay: boolean;
  location: string | null;
  htmlLink: string | null;
}

type View = "week" | "month";

// ─── Formatters (fr-FR) ─────────────────────────────────────────────────────
const timeFmt = new Intl.DateTimeFormat("fr-FR", { hour: "2-digit", minute: "2-digit" });
const weekdayShort = new Intl.DateTimeFormat("fr-FR", { weekday: "short" });
const weekdayLong = new Intl.DateTimeFormat("fr-FR", { weekday: "long", day: "numeric", month: "long" });
const monthYearFmt = new Intl.DateTimeFormat("fr-FR", { month: "long", year: "numeric" });
const dayMonthFmt = new Intl.DateTimeFormat("fr-FR", { day: "numeric", month: "long" });
const WEEKDAYS = ["lun.", "mar.", "mer.", "jeu.", "ven.", "sam.", "dim."];

// ─── Date helpers (lundi = début de semaine) ────────────────────────────────
function startOfDay(d: Date) {
  const x = new Date(d);
  x.setHours(0, 0, 0, 0);
  return x;
}
function addDays(d: Date, n: number) {
  const x = new Date(d);
  x.setDate(x.getDate() + n);
  return x;
}
function addMonths(d: Date, n: number) {
  const x = new Date(d);
  x.setMonth(x.getMonth() + n);
  return x;
}
function startOfWeek(d: Date) {
  const x = startOfDay(d);
  const day = (x.getDay() + 6) % 7; // 0 = lundi
  return addDays(x, -day);
}
function startOfMonth(d: Date) {
  const x = startOfDay(d);
  x.setDate(1);
  return x;
}
function sameDay(a: Date, b: Date) {
  return a.toDateString() === b.toDateString();
}
function eventDate(ev: CalEvent): Date {
  if (ev.allDay && ev.start) {
    const [y, m, d] = ev.start.split("-").map(Number);
    return new Date(y, m - 1, d);
  }
  return new Date(ev.start ?? Date.now());
}
function toLocalInput(d: Date) {
  const p = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}`;
}

export default function AgendaPage() {
  const me = useCurrentUser();
  const canWrite = me.role === "admin" || me.role === "super_admin";

  const [view, setView] = useState<View>("week");
  const [ref, setRef] = useState<Date>(() => startOfDay(new Date()));
  const [selected, setSelected] = useState<Date>(() => startOfDay(new Date()));
  const [events, setEvents] = useState<CalEvent[]>([]);
  const [loading, setLoading] = useState(true);
  const [problem, setProblem] = useState<"none" | "not_connected" | "reconnect" | "error">("none");

  // Form
  const [showForm, setShowForm] = useState(false);
  const [summary, setSummary] = useState("");
  const [start, setStart] = useState("");
  const [end, setEnd] = useState("");
  const [location, setLocation] = useState("");
  const [formError, setFormError] = useState<string | null>(null);
  const [saving, setSaving] = useState(false);

  // Plage chargée selon la vue
  const range = useMemo(() => {
    if (view === "week") {
      const from = startOfWeek(ref);
      return { from, to: addDays(from, 7) };
    }
    const monthStart = startOfMonth(ref);
    const from = startOfWeek(monthStart);
    const lastOfMonth = addDays(addMonths(monthStart, 1), -1);
    const to = addDays(startOfWeek(lastOfMonth), 7); // fin de la dernière semaine visible
    return { from, to };
  }, [view, ref]);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const url = `/backend/calendar/events?timeMin=${encodeURIComponent(
        range.from.toISOString()
      )}&timeMax=${encodeURIComponent(range.to.toISOString())}`;
      const res = await fetch(url, { credentials: "include" });
      if (res.status === 409) {
        const d = await res.json().catch(() => ({}));
        setProblem(d.error === "reconnect" ? "reconnect" : "not_connected");
        return;
      }
      if (!res.ok) {
        setProblem("error");
        return;
      }
      const data = await res.json();
      setProblem("none");
      setEvents(data.events);
    } catch {
      setProblem("error");
    } finally {
      setLoading(false);
    }
  }, [range]);

  useEffect(() => {
    load();
  }, [load]);

  // Index des événements par jour (clé = toDateString local)
  const byDay = useMemo(() => {
    const map = new Map<string, CalEvent[]>();
    for (const ev of events) {
      if (!ev.start) continue;
      const key = eventDate(ev).toDateString();
      if (!map.has(key)) map.set(key, []);
      map.get(key)!.push(ev);
    }
    return map;
  }, [events]);

  function navigate(dir: -1 | 1) {
    setRef((r) => (view === "week" ? addDays(r, dir * 7) : addMonths(r, dir)));
  }
  function goToday() {
    const t = startOfDay(new Date());
    setRef(t);
    setSelected(t);
  }

  function openCreate(day?: Date) {
    const base = day ?? selected ?? new Date();
    const s = new Date(base);
    s.setHours(9, 0, 0, 0);
    const e = new Date(base);
    e.setHours(9, 30, 0, 0);
    setStart(toLocalInput(s));
    setEnd(toLocalInput(e));
    setSummary("");
    setLocation("");
    setFormError(null);
    setShowForm(true);
  }

  async function createEvent(e: React.FormEvent) {
    e.preventDefault();
    setFormError(null);
    if (!summary || !start || !end) return setFormError("Titre, début et fin sont requis.");
    if (new Date(end) <= new Date(start)) return setFormError("La fin doit être après le début.");
    setSaving(true);
    try {
      const res = await fetch("/backend/calendar/events", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({
          summary,
          start: new Date(start).toISOString(),
          end: new Date(end).toISOString(),
          location: location || undefined,
        }),
      });
      if (!res.ok) {
        const d = await res.json().catch(() => ({}));
        return setFormError(d.message ?? "Échec de la création.");
      }
      setShowForm(false);
      await load();
    } catch {
      setFormError("Erreur réseau.");
    } finally {
      setSaving(false);
    }
  }

  async function remove(ev: CalEvent) {
    if (!window.confirm(`Supprimer « ${ev.summary} » ?`)) return;
    const res = await fetch(`/backend/calendar/events/${ev.id}`, {
      method: "DELETE",
      credentials: "include",
    });
    if (res.ok) await load();
  }

  const today = startOfDay(new Date());

  // Titre de la barre
  const title =
    view === "week"
      ? (() => {
          const s = startOfWeek(ref);
          const e = addDays(s, 6);
          return `${dayMonthFmt.format(s)} – ${dayMonthFmt.format(e)}`;
        })()
      : monthYearFmt.format(ref);

  return (
    <div className="mx-auto w-full max-w-4xl">
      {/* Barre d'outils */}
      <div className="mb-4 flex flex-col gap-3">
        <div className="flex items-center justify-between gap-2">
          <h1 className="text-xl font-semibold text-black sm:text-2xl dark:text-zinc-50">Agenda</h1>
          {canWrite && problem === "none" && (
            <button
              onClick={() => (showForm ? setShowForm(false) : openCreate())}
              className="rounded-lg bg-black px-3 py-2 text-sm font-medium text-white hover:bg-zinc-800 dark:bg-white dark:text-black dark:hover:bg-zinc-200"
            >
              {showForm ? "Annuler" : "+ Nouveau RDV"}
            </button>
          )}
        </div>

        <div className="flex flex-wrap items-center justify-between gap-2">
          {/* Sélecteur de vue */}
          <div className="inline-flex rounded-lg border border-zinc-300 p-0.5 dark:border-zinc-700">
            {(["week", "month"] as View[]).map((v) => (
              <button
                key={v}
                onClick={() => setView(v)}
                className={
                  "rounded-md px-3 py-1.5 text-sm font-medium " +
                  (view === v
                    ? "bg-black text-white dark:bg-white dark:text-black"
                    : "text-zinc-600 dark:text-zinc-400")
                }
              >
                {v === "week" ? "Semaine" : "Mois"}
              </button>
            ))}
          </div>

          {/* Navigation */}
          <div className="flex items-center gap-1">
            <button
              onClick={() => navigate(-1)}
              className="rounded-md border border-zinc-300 px-2.5 py-1.5 text-sm hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900"
              aria-label="Précédent"
            >
              ‹
            </button>
            <button
              onClick={goToday}
              className="rounded-md border border-zinc-300 px-3 py-1.5 text-sm hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900"
            >
              Aujourd&apos;hui
            </button>
            <button
              onClick={() => navigate(1)}
              className="rounded-md border border-zinc-300 px-2.5 py-1.5 text-sm hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900"
              aria-label="Suivant"
            >
              ›
            </button>
          </div>
        </div>

        <div className="text-sm font-medium capitalize text-zinc-500">{title}</div>
      </div>

      {/* États de problème */}
      {(problem === "not_connected" || problem === "reconnect") && (
        <div className="rounded-2xl border border-amber-300 bg-amber-50 p-5 text-sm text-amber-800 dark:border-amber-900 dark:bg-amber-950 dark:text-amber-200">
          {problem === "reconnect" ? "Votre connexion Google a expiré. " : "Votre compte Google n'est pas connecté. "}
          <Link href="/settings" className="font-medium underline">
            Aller dans Paramètres
          </Link>
          .
        </div>
      )}
      {problem === "error" && (
        <div className="rounded-2xl border border-red-300 bg-red-50 p-5 text-sm text-red-700 dark:border-red-900 dark:bg-red-950 dark:text-red-300">
          Impossible de charger l&apos;agenda pour le moment.
        </div>
      )}

      {/* Formulaire de création */}
      {showForm && canWrite && problem === "none" && (
        <form
          onSubmit={createEvent}
          className="mb-6 flex flex-col gap-3 rounded-2xl border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950"
        >
          <input
            placeholder="Titre du RDV"
            value={summary}
            onChange={(e) => setSummary(e.target.value)}
            required
            className="rounded-lg border border-zinc-300 px-3 py-2 text-sm dark:border-zinc-700 dark:bg-black"
          />
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
            <label className="flex flex-col gap-1 text-xs text-zinc-500">
              Début
              <input type="datetime-local" value={start} onChange={(e) => setStart(e.target.value)} required className="rounded-lg border border-zinc-300 px-3 py-2 text-sm dark:border-zinc-700 dark:bg-black" />
            </label>
            <label className="flex flex-col gap-1 text-xs text-zinc-500">
              Fin
              <input type="datetime-local" value={end} onChange={(e) => setEnd(e.target.value)} required className="rounded-lg border border-zinc-300 px-3 py-2 text-sm dark:border-zinc-700 dark:bg-black" />
            </label>
          </div>
          <input
            placeholder="Lieu (optionnel)"
            value={location}
            onChange={(e) => setLocation(e.target.value)}
            className="rounded-lg border border-zinc-300 px-3 py-2 text-sm dark:border-zinc-700 dark:bg-black"
          />
          {formError && <p className="text-sm text-red-600">{formError}</p>}
          <button type="submit" disabled={saving} className="self-start rounded-lg bg-black px-4 py-2 text-sm font-medium text-white hover:bg-zinc-800 disabled:opacity-60 dark:bg-white dark:text-black dark:hover:bg-zinc-200">
            {saving ? "Création…" : "Créer le RDV"}
          </button>
        </form>
      )}

      {problem === "none" && (loading ? (
        <p className="text-sm text-zinc-500">Chargement…</p>
      ) : view === "week" ? (
        <WeekView refDate={ref} byDay={byDay} today={today} canWrite={canWrite} onRemove={remove} onAdd={openCreate} />
      ) : (
        <MonthView refDate={ref} byDay={byDay} today={today} selected={selected} onSelect={setSelected} canWrite={canWrite} onRemove={remove} onAdd={openCreate} />
      ))}
    </div>
  );
}

// ─── Vue Semaine : 7 jours empilés (mobile-first) ───────────────────────────
function WeekView({
  refDate,
  byDay,
  today,
  canWrite,
  onRemove,
  onAdd,
}: {
  refDate: Date;
  byDay: Map<string, CalEvent[]>;
  today: Date;
  canWrite: boolean;
  onRemove: (ev: CalEvent) => void;
  onAdd: (day: Date) => void;
}) {
  const start = startOfWeek(refDate);
  const days = Array.from({ length: 7 }, (_, i) => addDays(start, i));
  return (
    <div className="flex flex-col gap-3">
      {days.map((day) => {
        const evs = (byDay.get(day.toDateString()) ?? []).sort(
          (a, b) => eventDate(a).getTime() - eventDate(b).getTime()
        );
        const isToday = sameDay(day, today);
        return (
          <div
            key={day.toISOString()}
            className={
              "rounded-2xl border bg-white p-4 dark:bg-zinc-950 " +
              (isToday ? "border-black dark:border-zinc-300" : "border-zinc-200 dark:border-zinc-800")
            }
          >
            <div className="mb-2 flex items-center justify-between">
              <h2 className="text-sm font-medium capitalize text-zinc-700 dark:text-zinc-300">
                {weekdayLong.format(day)} {isToday && <span className="text-xs text-zinc-400">· aujourd&apos;hui</span>}
              </h2>
              {canWrite && (
                <button onClick={() => onAdd(day)} className="text-xs text-zinc-400 hover:text-black dark:hover:text-white" aria-label="Ajouter un RDV ce jour">
                  + RDV
                </button>
              )}
            </div>
            {evs.length === 0 ? (
              <p className="text-xs text-zinc-400">Aucun rendez-vous.</p>
            ) : (
              <ul className="flex flex-col gap-2">
                {evs.map((ev) => (
                  <EventRow key={ev.id} ev={ev} canWrite={canWrite} onRemove={onRemove} />
                ))}
              </ul>
            )}
          </div>
        );
      })}
    </div>
  );
}

// ─── Vue Mois : grille + détail du jour sélectionné ─────────────────────────
function MonthView({
  refDate,
  byDay,
  today,
  selected,
  onSelect,
  canWrite,
  onRemove,
  onAdd,
}: {
  refDate: Date;
  byDay: Map<string, CalEvent[]>;
  today: Date;
  selected: Date;
  onSelect: (d: Date) => void;
  canWrite: boolean;
  onRemove: (ev: CalEvent) => void;
  onAdd: (day: Date) => void;
}) {
  const monthStart = startOfMonth(refDate);
  const gridStart = startOfWeek(monthStart);
  const lastOfMonth = addDays(addMonths(monthStart, 1), -1);
  const weeks = Math.ceil((addDays(startOfWeek(lastOfMonth), 7).getTime() - gridStart.getTime()) / (7 * 86400000));
  const cells = Array.from({ length: weeks * 7 }, (_, i) => addDays(gridStart, i));

  const selectedEvents = (byDay.get(selected.toDateString()) ?? []).sort(
    (a, b) => eventDate(a).getTime() - eventDate(b).getTime()
  );

  return (
    <div className="flex flex-col gap-4">
      <div className="rounded-2xl border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-950">
        <div className="grid grid-cols-7 text-center text-xs font-medium text-zinc-400">
          {WEEKDAYS.map((w) => (
            <div key={w} className="py-1">{w}</div>
          ))}
        </div>
        <div className="grid grid-cols-7 gap-1">
          {cells.map((day) => {
            const inMonth = day.getMonth() === monthStart.getMonth();
            const isToday = sameDay(day, today);
            const isSelected = sameDay(day, selected);
            const count = byDay.get(day.toDateString())?.length ?? 0;
            return (
              <button
                key={day.toISOString()}
                onClick={() => onSelect(day)}
                className={
                  "flex aspect-square flex-col items-center justify-start rounded-lg p-1 text-sm transition-colors " +
                  (isSelected
                    ? "bg-black text-white dark:bg-white dark:text-black"
                    : isToday
                      ? "bg-zinc-100 dark:bg-zinc-900"
                      : "hover:bg-zinc-100 dark:hover:bg-zinc-900") +
                  (inMonth ? "" : " text-zinc-300 dark:text-zinc-700")
                }
              >
                <span className={isToday && !isSelected ? "font-semibold" : ""}>{day.getDate()}</span>
                {count > 0 && (
                  <span
                    className={
                      "mt-0.5 h-1.5 w-1.5 rounded-full " +
                      (isSelected ? "bg-white dark:bg-black" : "bg-black dark:bg-white")
                    }
                    title={`${count} rendez-vous`}
                  />
                )}
              </button>
            );
          })}
        </div>
      </div>

      {/* Détail du jour sélectionné */}
      <div className="rounded-2xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950">
        <div className="mb-2 flex items-center justify-between">
          <h2 className="text-sm font-medium capitalize text-zinc-700 dark:text-zinc-300">
            {weekdayLong.format(selected)}
          </h2>
          {canWrite && (
            <button onClick={() => onAdd(selected)} className="text-xs text-zinc-400 hover:text-black dark:hover:text-white">
              + RDV
            </button>
          )}
        </div>
        {selectedEvents.length === 0 ? (
          <p className="text-xs text-zinc-400">Aucun rendez-vous ce jour.</p>
        ) : (
          <ul className="flex flex-col gap-2">
            {selectedEvents.map((ev) => (
              <EventRow key={ev.id} ev={ev} canWrite={canWrite} onRemove={onRemove} />
            ))}
          </ul>
        )}
      </div>
    </div>
  );
}

// ─── Ligne d'événement réutilisable ─────────────────────────────────────────
function EventRow({ ev, canWrite, onRemove }: { ev: CalEvent; canWrite: boolean; onRemove: (ev: CalEvent) => void }) {
  return (
    <li className="flex items-start justify-between gap-3 rounded-xl border border-zinc-200 p-3 dark:border-zinc-800">
      <div className="min-w-0">
        <div className="truncate font-medium text-black dark:text-zinc-50">{ev.summary}</div>
        <div className="mt-0.5 text-xs text-zinc-500">
          {ev.allDay
            ? "Toute la journée"
            : ev.start
              ? `${timeFmt.format(new Date(ev.start))}${ev.end ? " – " + timeFmt.format(new Date(ev.end)) : ""}`
              : ""}
          {ev.location ? ` · ${ev.location}` : ""}
        </div>
      </div>
      {canWrite && (
        <button
          onClick={() => onRemove(ev)}
          className="shrink-0 rounded-md border border-zinc-300 px-2 py-1 text-xs text-zinc-500 hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900"
          aria-label="Supprimer"
        >
          ✕
        </button>
      )}
    </li>
  );
}
