"use client";

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

interface DriveFile {
  id: string;
  name: string;
  mimeType: string;
  isFolder: boolean;
  size: number | null;
  modifiedTime: string | null;
  webViewLink: string | null;
}

interface Crumb {
  id: string;
  name: string;
}

const ROOT: Crumb = { id: "root", name: "Documents" };
const dateFmt = new Intl.DateTimeFormat("fr-FR", { day: "numeric", month: "short", year: "numeric" });

function fmtSize(n: number | null) {
  if (n == null) return "";
  if (n < 1024) return `${n} o`;
  if (n < 1024 * 1024) return `${Math.round(n / 1024)} Ko`;
  return `${(n / 1024 / 1024).toFixed(1)} Mo`;
}

function fileIcon(f: DriveFile) {
  if (f.isFolder) return "📁";
  const m = f.mimeType;
  if (m.includes("spreadsheet")) return "📊";
  if (m.includes("document")) return "📝";
  if (m.includes("presentation")) return "📽️";
  if (m.startsWith("image/")) return "🖼️";
  if (m === "application/pdf") return "📕";
  if (m.startsWith("video/")) return "🎬";
  if (m.startsWith("audio/")) return "🎵";
  return "📄";
}

async function fetchFolders(folderId: string): Promise<Crumb[]> {
  const res = await fetch(`/backend/drive/files?folderId=${encodeURIComponent(folderId)}`, {
    credentials: "include",
  });
  if (!res.ok) throw new Error("fetch");
  const data = await res.json();
  return (data.files as DriveFile[])
    .filter((f) => f.isFolder)
    .map((f) => ({ id: f.id, name: f.name }));
}

// ─── Nœud d'arborescence (dossiers, chargés à la demande) ───────────────────
function TreeNode({
  node,
  ancestors,
  currentId,
  refreshKey,
  onSelect,
}: {
  node: Crumb;
  ancestors: Crumb[];
  currentId: string;
  refreshKey: number;
  onSelect: (node: Crumb, ancestors: Crumb[]) => void;
}) {
  const [expanded, setExpanded] = useState(false);
  const [children, setChildren] = useState<Crumb[] | null>(null);

  // Charge les sous-dossiers dès l'affichage (pour savoir s'il faut un chevron) + après modif.
  useEffect(() => {
    let on = true;
    fetchFolders(node.id)
      .then((f) => on && setChildren(f))
      .catch(() => on && setChildren([]));
    return () => {
      on = false;
    };
  }, [node.id, refreshKey]);

  const hasChildren = (children?.length ?? 0) > 0;
  const isCurrent = currentId === node.id;
  return (
    <div>
      <div className={"flex items-center gap-1 rounded-md px-1 py-1 " + (isCurrent ? "bg-zinc-100 dark:bg-zinc-900" : "")}>
        {hasChildren ? (
          <button
            onClick={() => setExpanded((e) => !e)}
            className="w-4 shrink-0 text-zinc-400 hover:text-black dark:hover:text-white"
            aria-label={expanded ? "Réduire" : "Développer"}
          >
            {expanded ? "▾" : "▸"}
          </button>
        ) : (
          <span className="w-4 shrink-0" aria-hidden />
        )}
        <button
          onClick={() => onSelect(node, ancestors)}
          className={"flex min-w-0 flex-1 items-center gap-1.5 text-left text-sm " + (isCurrent ? "font-medium text-black dark:text-zinc-50" : "text-zinc-600 dark:text-zinc-300")}
        >
          <span aria-hidden>📁</span>
          <span className="truncate">{node.name}</span>
        </button>
      </div>
      {expanded && hasChildren && (
        <div className="ml-3 border-l border-zinc-200 pl-1 dark:border-zinc-800">
          {children!.map((c) => (
            <TreeNode
              key={c.id}
              node={c}
              ancestors={[...ancestors, c]}
              currentId={currentId}
              refreshKey={refreshKey}
              onSelect={onSelect}
            />
          ))}
        </div>
      )}
    </div>
  );
}

// Arborescence : on affiche directement les dossiers de la racine (sans nœud « Documents »).
function RootTree({
  currentId,
  refreshKey,
  onSelect,
}: {
  currentId: string;
  refreshKey: number;
  onSelect: (node: Crumb, ancestors: Crumb[]) => void;
}) {
  const [folders, setFolders] = useState<Crumb[] | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let on = true;
    setLoading(true);
    fetchFolders("root")
      .then((f) => on && setFolders(f))
      .catch(() => on && setFolders([]))
      .finally(() => on && setLoading(false));
    return () => {
      on = false;
    };
  }, [refreshKey]);

  if (loading && folders === null) return <div className="px-2 py-1 text-xs text-zinc-400">…</div>;
  if (!folders || folders.length === 0)
    return <div className="px-2 py-1 text-xs text-zinc-400">Aucun dossier</div>;

  return (
    <>
      {folders.map((c) => (
        <TreeNode
          key={c.id}
          node={c}
          ancestors={[ROOT, c]}
          currentId={currentId}
          refreshKey={refreshKey}
          onSelect={onSelect}
        />
      ))}
    </>
  );
}

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

  const [path, setPath] = useState<Crumb[]>([ROOT]);
  const currentId = path[path.length - 1].id;

  const [files, setFiles] = useState<DriveFile[]>([]);
  const [loading, setLoading] = useState(true);
  const [problem, setProblem] = useState<"none" | "not_connected" | "reconnect" | "error">("none");
  const [search, setSearch] = useState("");
  const [activeSearch, setActiveSearch] = useState("");
  const [busy, setBusy] = useState(false);
  const [showTree, setShowTree] = useState(false);
  const [treeKey, setTreeKey] = useState(0); // force le rechargement de l'arborescence
  const [moving, setMoving] = useState<{ file: DriveFile; fromId: string } | null>(null);
  const [viewing, setViewing] = useState<DriveFile | null>(null);
  const fileInput = useRef<HTMLInputElement>(null);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const url = activeSearch
        ? `/backend/drive/files?q=${encodeURIComponent(activeSearch)}`
        : `/backend/drive/files?folderId=${encodeURIComponent(currentId)}`;
      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");
      setFiles(data.files);
    } catch {
      setProblem("error");
    } finally {
      setLoading(false);
    }
  }, [currentId, activeSearch]);

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

  function selectFolder(node: Crumb, ancestors: Crumb[]) {
    setActiveSearch("");
    setSearch("");
    setPath(ancestors);
    setShowTree(false);
  }
  function openFolder(f: DriveFile) {
    setActiveSearch("");
    setSearch("");
    if (activeSearch) setPath([ROOT, { id: f.id, name: f.name }]);
    else setPath((p) => [...p, { id: f.id, name: f.name }]);
  }
  function goCrumb(i: number) {
    setActiveSearch("");
    setSearch("");
    setPath((p) => p.slice(0, i + 1));
  }

  async function afterMutation(affectsFolders: boolean) {
    await load();
    if (affectsFolders) setTreeKey((k) => k + 1);
  }

  async function onUpload(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    setBusy(true);
    try {
      const fd = new FormData();
      fd.append("file", file);
      fd.append("folderId", currentId);
      const res = await fetch("/backend/drive/files", { method: "POST", credentials: "include", body: fd });
      if (res.ok) await afterMutation(false);
    } finally {
      setBusy(false);
      if (fileInput.current) fileInput.current.value = "";
    }
  }

  async function newFolder() {
    const name = window.prompt("Nom du nouveau dossier :");
    if (!name) return;
    setBusy(true);
    try {
      const res = await fetch("/backend/drive/folders", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ name, parentId: currentId }),
      });
      if (res.ok) await afterMutation(true);
    } finally {
      setBusy(false);
    }
  }

  async function rename(f: DriveFile) {
    const name = window.prompt("Nouveau nom :", f.name);
    if (!name || name === f.name) return;
    setBusy(true);
    try {
      const res = await fetch(`/backend/drive/files/${f.id}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ name }),
      });
      if (res.ok) await afterMutation(f.isFolder);
    } finally {
      setBusy(false);
    }
  }

  async function remove(f: DriveFile) {
    if (!window.confirm(`Mettre « ${f.name} » à la corbeille ?`)) return;
    setBusy(true);
    try {
      const res = await fetch(`/backend/drive/files/${f.id}`, { method: "DELETE", credentials: "include" });
      if (res.ok) await afterMutation(f.isFolder);
    } finally {
      setBusy(false);
    }
  }

  async function moveHere() {
    if (!moving) return;
    setBusy(true);
    try {
      const res = await fetch(`/backend/drive/files/${moving.file.id}/move`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify({ targetFolderId: currentId }),
      });
      if (res.ok) {
        setMoving(null);
        await afterMutation(true);
      } else {
        const d = await res.json().catch(() => ({}));
        window.alert(d.message ?? "Déplacement impossible.");
      }
    } finally {
      setBusy(false);
    }
  }

  // ── Problèmes ─────────────────────────────────────────────────────────────
  if (problem === "not_connected" || problem === "reconnect") {
    return (
      <div className="mx-auto w-full max-w-5xl">
        <h1 className="mb-6 text-xl font-semibold text-black sm:text-2xl dark:text-zinc-50">Documents</h1>
        <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"
            ? "L'accès à Drive nécessite d'autoriser une permission supplémentaire. "
            : "Votre compte Google n'est pas connecté. "}
          <Link href="/settings" className="font-medium underline">Aller dans Paramètres</Link>.
        </div>
      </div>
    );
  }

  return (
    <div className="mx-auto w-full max-w-5xl">
      <div className="mb-4 flex flex-wrap items-center justify-between gap-2">
        <h1 className="text-xl font-semibold text-black sm:text-2xl dark:text-zinc-50">Google Drive</h1>
        {canWrite && (
          <div className="flex gap-2">
            <button onClick={newFolder} disabled={busy} className="rounded-lg border border-zinc-300 px-3 py-2 text-sm hover:bg-zinc-100 disabled:opacity-50 dark:border-zinc-700 dark:hover:bg-zinc-900">
              + Dossier
            </button>
            <button onClick={() => fileInput.current?.click()} disabled={busy} className="rounded-lg bg-black px-3 py-2 text-sm font-medium text-white hover:bg-zinc-800 disabled:opacity-50 dark:bg-white dark:text-black dark:hover:bg-zinc-200">
              {busy ? "…" : "Importer"}
            </button>
            <input ref={fileInput} type="file" onChange={onUpload} className="hidden" />
          </div>
        )}
      </div>

      {/* Recherche */}
      <form
        onSubmit={(e) => { e.preventDefault(); setActiveSearch(search.trim()); }}
        className="mb-4 flex gap-2"
      >
        <input
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          placeholder="Rechercher dans le Drive…"
          className="flex-1 rounded-lg border border-zinc-300 px-3 py-2 text-sm dark:border-zinc-700 dark:bg-black"
        />
        <button type="submit" className="rounded-lg border border-zinc-300 px-3 py-2 text-sm hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900">
          Rechercher
        </button>
        {activeSearch && (
          <button type="button" onClick={() => { setActiveSearch(""); setSearch(""); }} className="rounded-lg border border-zinc-300 px-3 py-2 text-sm hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900">
            Effacer
          </button>
        )}
      </form>

      <div className="flex flex-col gap-4 md:flex-row md:items-start">
        {/* Arborescence */}
        <aside className="md:w-64 md:shrink-0">
          <button
            onClick={() => setShowTree((s) => !s)}
            className="mb-2 flex w-full items-center justify-between rounded-lg border border-zinc-300 px-3 py-2 text-sm md:hidden dark:border-zinc-700"
          >
            <span>Arborescence</span>
            <span>{showTree ? "▾" : "▸"}</span>
          </button>
          <div className={(showTree ? "block" : "hidden") + " max-h-[60vh] overflow-auto rounded-2xl border border-zinc-200 bg-white p-2 md:block dark:border-zinc-800 dark:bg-zinc-950"}>
            <RootTree key={treeKey} currentId={currentId} refreshKey={treeKey} onSelect={selectFolder} />
          </div>
        </aside>

        {/* Contenu du dossier courant */}
        <div className="min-w-0 flex-1">
          {/* Fil d'Ariane / résultats de recherche */}
          {!activeSearch ? (
            <nav className="mb-3 flex flex-wrap items-center gap-1 text-sm text-zinc-500">
              {path.map((c, i) => (
                <span key={c.id} className="flex items-center gap-1">
                  {i > 0 && <span className="text-zinc-300">/</span>}
                  <button
                    onClick={() => goCrumb(i)}
                    className={i === path.length - 1 ? "font-medium text-black dark:text-zinc-50" : "hover:underline"}
                  >
                    {c.name}
                  </button>
                </span>
              ))}
            </nav>
          ) : (
            <p className="mb-3 text-sm text-zinc-500">Résultats pour « {activeSearch} »</p>
          )}

          {problem === "error" && (
            <div className="mb-4 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 le Drive pour le moment.
            </div>
          )}

          {moving && (
            <div className="mb-3 flex flex-wrap items-center justify-between gap-2 rounded-lg border border-blue-300 bg-blue-50 px-3 py-2 text-sm text-blue-800 dark:border-blue-900 dark:bg-blue-950 dark:text-blue-200">
              <span className="min-w-0 truncate">
                Déplacement de « {moving.file.name} » — ouvrez le dossier de destination puis cliquez « Déplacer ici ».
              </span>
              <span className="flex shrink-0 gap-2">
                <button
                  onClick={moveHere}
                  disabled={busy || currentId === moving.fromId || currentId === moving.file.id || activeSearch !== ""}
                  className="rounded-md bg-blue-600 px-3 py-1 text-xs font-medium text-white hover:bg-blue-700 disabled:opacity-40"
                >
                  Déplacer ici
                </button>
                <button onClick={() => setMoving(null)} className="rounded-md border border-blue-300 px-3 py-1 text-xs dark:border-blue-800">
                  Annuler
                </button>
              </span>
            </div>
          )}

          {loading ? (
            <p className="text-sm text-zinc-500">Chargement…</p>
          ) : files.length === 0 ? (
            <p className="rounded-2xl border border-zinc-200 bg-white p-5 text-sm text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950">
              {activeSearch ? "Aucun résultat." : "Dossier vide."}
            </p>
          ) : (
            <ul className="flex flex-col gap-1.5">
              {files.map((f) => (
                <li
                  key={f.id}
                  className="flex flex-col gap-2 rounded-xl border border-zinc-200 bg-white p-3 sm:flex-row sm:items-center sm:justify-between sm:gap-3 dark:border-zinc-800 dark:bg-zinc-950"
                >
                  <button
                    onClick={() => (f.isFolder ? openFolder(f) : setViewing(f))}
                    className="flex min-w-0 flex-1 cursor-pointer items-center gap-3 text-left"
                  >
                    <span className="text-lg" aria-hidden>{fileIcon(f)}</span>
                    <span className="min-w-0 flex-1">
                      <span className="block truncate text-sm font-medium text-black dark:text-zinc-50">{f.name}</span>
                      <span className="block text-xs text-zinc-400">
                        {f.isFolder ? "Dossier" : fmtSize(f.size)}
                        {f.modifiedTime ? ` · ${dateFmt.format(new Date(f.modifiedTime))}` : ""}
                      </span>
                    </span>
                    {f.isFolder && <span className="text-zinc-300 dark:text-zinc-600" aria-hidden>›</span>}
                  </button>

                  <div className="flex w-full items-center gap-1.5 text-xs sm:w-auto sm:shrink-0">
                    <div className="flex flex-wrap items-center gap-1.5">
                      {!f.isFolder && (
                        <a href={`/backend/drive/files/${f.id}/download`} className="rounded-md border border-zinc-300 px-2 py-1 hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900">
                          Télécharger
                        </a>
                      )}
                      {canWrite && (
                        <button onClick={() => setMoving({ file: f, fromId: currentId })} disabled={busy} className="rounded-md border border-blue-300 px-2 py-1 text-blue-700 hover:bg-blue-50 disabled:opacity-50 dark:border-blue-900 dark:text-blue-400 dark:hover:bg-blue-950">
                          Déplacer
                        </button>
                      )}
                      {canWrite && (
                        <button onClick={() => rename(f)} disabled={busy} className="rounded-md border border-zinc-300 px-2 py-1 hover:bg-zinc-100 disabled:opacity-50 dark:border-zinc-700 dark:hover:bg-zinc-900">
                          Renommer
                        </button>
                      )}
                    </div>
                    {canWrite && (
                      <button onClick={() => remove(f)} disabled={busy} className="ml-auto sm:ml-3 rounded-md border border-red-300 px-2 py-1 text-red-600 hover:bg-red-50 disabled:opacity-50 dark:border-red-900 dark:hover:bg-red-950">
                        Supprimer
                      </button>
                    )}
                  </div>
                </li>
              ))}
            </ul>
          )}
        </div>
      </div>

      {/* Visualiseur intégré (sert le fichier via le backend, sans passer par Google) */}
      {viewing && (
        <div className="fixed inset-0 z-[60] flex flex-col bg-black/85">
          <div className="flex items-center justify-between gap-3 bg-white px-4 py-2 dark:bg-zinc-900">
            <span className="min-w-0 truncate text-sm font-medium text-black dark:text-zinc-50">{viewing.name}</span>
            <div className="flex shrink-0 items-center gap-2 text-sm">
              <a href={`/backend/drive/files/${viewing.id}/download`} className="rounded-md border border-zinc-300 px-3 py-1.5 hover:bg-zinc-100 dark:border-zinc-700 dark:hover:bg-zinc-900">
                Télécharger
              </a>
              <button onClick={() => setViewing(null)} className="rounded-md bg-black px-3 py-1.5 font-medium text-white dark:bg-white dark:text-black">
                Fermer ✕
              </button>
            </div>
          </div>
          <div className="flex flex-1 items-center justify-center overflow-auto p-2">
            {(() => {
              const url = `/backend/drive/files/${viewing.id}/view`;
              const m = viewing.mimeType || "";
              if (m.startsWith("image/"))
                // eslint-disable-next-line @next/next/no-img-element
                return <img src={url} alt={viewing.name} className="max-h-full max-w-full object-contain" />;
              if (m === "application/pdf" || m.startsWith("application/vnd.google-apps") || m.startsWith("text/"))
                return <iframe src={url} title={viewing.name} className="h-full w-full rounded bg-white" />;
              if (m.startsWith("video/")) return <video src={url} controls className="max-h-full max-w-full" />;
              if (m.startsWith("audio/")) return <audio src={url} controls />;
              return (
                <div className="text-center text-white">
                  <p className="mb-3">Aperçu non disponible pour ce type de fichier.</p>
                  <a href={`/backend/drive/files/${viewing.id}/download`} className="rounded-lg bg-white px-4 py-2 text-sm font-medium text-black">
                    Télécharger
                  </a>
                </div>
              );
            })()}
          </div>
        </div>
      )}
    </div>
  );
}
