"use client";

import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Dialog } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { IconClock } from "@/components/icons";

const IDLE_MS = 60 * 60 * 1000; // 1 heure d'inactivité

// Surveille l'activité utilisateur (souris, clavier, scroll, touch). Au bout
// de IDLE_MS sans aucun événement, déclenche une modale forcée de
// reconnexion. La modale n'a pas de close discret — seule action possible :
// "Se reconnecter" qui POST logout + redirect /login.
//
// Catch aussi les réponses HTTP 401 venant de nos Route Handlers via un
// override de window.fetch (renvoyé en cleanup au démount). Permet de
// forcer la modale dès qu'une session backend devient invalide, même
// avant les 60min d'idle (cas du JWT mobile expiré à 15min).

export function IdleSessionGuard() {
  const [expired, setExpired] = useState(false);
  const [pendingLogout, setPendingLogout] = useState(false);
  const router = useRouter();

  // Activity timer
  useEffect(() => {
    let timer: ReturnType<typeof setTimeout> | null = null;
    function arm() {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => setExpired(true), IDLE_MS);
    }
    arm();
    const events: (keyof DocumentEventMap)[] = [
      "mousemove",
      "keydown",
      "click",
      "touchstart",
      "scroll",
    ];
    const handler = () => arm();
    events.forEach((e) =>
      document.addEventListener(e, handler, { passive: true }),
    );
    return () => {
      if (timer) clearTimeout(timer);
      events.forEach((e) => document.removeEventListener(e, handler));
    };
  }, []);

  // 401 detection on internal API calls
  useEffect(() => {
    const original = window.fetch;
    window.fetch = async (...args) => {
      const res = await original(...args);
      if (res.status === 401) {
        let url = "";
        try {
          if (typeof args[0] === "string") url = args[0];
          else if (args[0] instanceof URL) url = args[0].pathname;
          else if (args[0] instanceof Request) url = args[0].url;
        } catch {
          /* ignore */
        }
        // Filtre : on ne déclenche que pour nos Route Handlers /api/*, pas
        // pour les ressources statiques ou autres providers tiers.
        if (url.includes("/api/") && !url.includes("/api/auth/login")) {
          setExpired(true);
        }
      }
      return res;
    };
    return () => {
      window.fetch = original;
    };
  }, []);

  async function handleRelogin() {
    setPendingLogout(true);
    try {
      // Appelle le logout côté Next (clear cookie). Si le backend renvoie
      // 401 ici, peu importe — clearSession local s'exécute quand même.
      await fetch("/api/auth/logout", { method: "POST" });
    } catch {
      /* ignore */
    }
    router.replace("/login");
    router.refresh();
  }

  return (
    <Dialog
      open={expired}
      // Pas de fermeture discrète : la modale reste ouverte tant que
      // l'utilisateur n'a pas cliqué "Se reconnecter". onOpenChange est
      // un no-op pour empêcher Escape ou click-outside de la fermer.
      onOpenChange={() => {
        /* lock open */
      }}
      title="Session expirée"
      description="Aucune activité détectée depuis 1 heure. Pour des raisons de sécurité, ta session a été terminée."
      footer={
        <Button onClick={handleRelogin} loading={pendingLogout} type="button">
          Se reconnecter
        </Button>
      }
    >
      <div className="flex items-start gap-3">
        <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-warning-subtle text-warning ring-1 ring-amber-200">
          <IconClock size={18} />
        </div>
        <p className="text-sm text-foreground leading-relaxed">
          Tu vas être redirigé vers la page de connexion. Les choix non
          sauvegardés (templates en cours de configuration, etc.) seront
          perdus — pense à valider les opérations critiques avant les
          longues pauses.
        </p>
      </div>
    </Dialog>
  );
}
