/* global React, Icon, Button, RemoteCard, PageHead, StatusDot, useLiveDevices, SyncNotice */
// ============================================================
// BIBLIOTHÈQUE DE MÉDIAS CENTRALE (backend/media) + DOSSIER AUTO PAR IPHONE.
//  - Tout vit au MÊME endroit (chemin disque affiché). En plus du pool libre, un dossier
//    réservé "Téléphones/" contient un sous-dossier AUTO par iPhone (à son nom).
//  - La vue d'un iPhone NAVIGUE DANS son dossier : créer un dossier / ajouter du contenu y
//    va automatiquement, et l'envoi cible ce téléphone. "Mettre du contenu sur un tel" =
//    déplacer un dossier de la bibliothèque vers Téléphones/<nom>.
//  - L'opérateur voit, dans sa télécommande, le dossier de SON iPhone et envoie en 1 clic.
//  - Créer/déplacer/renommer/supprimer dans l'UI ⇄ se répercute sur le disque (même nom).
// ============================================================
function fmtSize(n) { return n > 1048576 ? (n / 1048576).toFixed(1) + " Mo" : Math.max(1, Math.round(n / 1024)) + " Ko"; }
const PHONES_DIR = "Téléphones";

// ---- Aperçu plein écran (image/vidéo) + envoi ----
function PreviewModal({ fileUrl, f, onClose, onPush, pushing, canPush }) {
  if (!f) return null;
  const isImg = f.kind === "image";
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 1000, background: "rgba(4,7,15,.78)", backdropFilter: "blur(3px)", display: "grid", placeItems: "center", padding: 20 }}>
      <div onClick={e => e.stopPropagation()} style={{ width: "min(560px, 94vw)", maxHeight: "92vh", display: "flex", flexDirection: "column", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--r-lg)", overflow: "hidden", boxShadow: "0 24px 70px rgba(0,0,0,.5)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "11px 14px", borderBottom: "1px solid var(--border)" }}>
          {React.createElement(Icon[isImg ? "image" : "play"], { size: 16, color: "var(--muted)" })}
          <div style={{ flex: 1, minWidth: 0, fontSize: 13.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }} title={f.name}>{f.name}</div>
          <button onClick={onClose} style={{ width: 30, height: 30, display: "grid", placeItems: "center", borderRadius: 8, background: "var(--surface-3)", border: "1px solid var(--border)", color: "var(--muted)", cursor: "pointer" }}>{React.createElement(Icon.x, { size: 15 })}</button>
        </div>
        <div style={{ flex: 1, minHeight: 0, background: "#0b1020", display: "grid", placeItems: "center", padding: 10 }}>
          {isImg
            ? <img src={fileUrl} alt={f.name} style={{ maxWidth: "100%", maxHeight: "62vh", objectFit: "contain", borderRadius: 6 }} />
            : <video src={fileUrl} controls autoPlay style={{ maxWidth: "100%", maxHeight: "62vh", borderRadius: 6 }} />}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "12px 14px", borderTop: "1px solid var(--border)" }}>
          <span className="mono" style={{ fontSize: 11, color: "var(--faint)", flex: 1 }}>{f.kind} · {fmtSize(f.size)}</span>
          {canPush && <Button variant="primary" icon="send" onClick={() => onPush(f.name)} disabled={pushing === f.name}>
            {pushing === f.name ? "Envoi…" : "Envoyer au téléphone"}
          </Button>}
        </div>
      </div>
    </div>
  );
}

// ---- Modale "déplacer un dossier" : racine, dossiers du pool, ou dossier d'un iPhone ----
function MoveModal({ item, onClose, onMove }) {
  const { useState, useEffect } = React;
  const [dests, setDests] = useState(null);
  useEffect(() => {
    (async () => {
      const root = await window.Backend.libBrowse("");
      const phones = await window.Backend.libBrowse(PHONES_DIR);
      const excl = (pp) => pp === item.path || pp.startsWith(item.path + "/") || item.path.startsWith(pp + "/");
      const opts = [{ label: "↩  (Racine de la bibliothèque)", path: "" }];
      (root && root.folders ? root.folders : []).filter(f => f.name !== PHONES_DIR && !excl(f.path)).forEach(f => opts.push({ label: f.name, path: f.path }));
      (phones && phones.folders ? phones.folders : []).filter(f => !excl(f.path)).forEach(f => opts.push({ label: "📱  " + f.name, path: f.path }));
      setDests(opts);
    })();
  }, [item.path]);
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 1001, background: "rgba(4,7,15,.78)", backdropFilter: "blur(3px)", display: "grid", placeItems: "center", padding: 20 }}>
      <div onClick={e => e.stopPropagation()} style={{ width: "min(440px,94vw)", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--r-lg)", overflow: "hidden" }}>
        <div style={{ padding: "12px 14px", borderBottom: "1px solid var(--border)", fontSize: 13.5, fontWeight: 700 }}>Déplacer « {item.name} » vers…</div>
        <div style={{ maxHeight: "60vh", overflow: "auto", padding: 8 }}>
          {dests === null ? <div style={{ color: "var(--faint)", fontSize: 12, padding: 10 }}>Chargement…</div>
            : dests.length === 0 ? <div style={{ color: "var(--faint)", fontSize: 12, padding: 10 }}>Aucune destination possible.</div>
            : dests.map(d => (
              <button key={d.path} onClick={() => onMove(d.path)} style={{ width: "100%", textAlign: "left", display: "flex", alignItems: "center", gap: 9, padding: "10px 11px", borderRadius: 9, background: "var(--surface-2)", border: "1px solid var(--border)", color: "var(--text)", cursor: "pointer", marginBottom: 6, fontSize: 13 }}>
                {d.label}
              </button>
            ))}
        </div>
        <div style={{ padding: "10px 14px", borderTop: "1px solid var(--border)", textAlign: "right" }}>
          <Button variant="ghost" onClick={onClose}>Annuler</Button>
        </div>
      </div>
    </div>
  );
}

// ---- Tuile dossier ----
function FolderTile({ folder, canEdit, devices, onOpen, onRename, onMove, onDelete }) {
  const ownerDev = folder.assigned && devices ? devices.find(d => (d.udid || d.id) === folder.assigned) : null;
  const isPhone = folder.path === PHONES_DIR;
  return (
    <div style={{ border: "1px solid var(--border)", borderRadius: 11, padding: "12px 12px", background: "var(--surface-2)", display: "flex", flexDirection: "column", gap: 9 }}>
      <div onClick={onOpen} style={{ cursor: "pointer", display: "flex", alignItems: "center", gap: 11 }}>
        <div style={{ width: 38, height: 38, borderRadius: 9, background: "var(--accent-soft)", display: "grid", placeItems: "center", color: "var(--accent)" }}>{React.createElement(isPhone ? Icon.phone : Icon.grid, { size: 18 })}</div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }} title={folder.name}>{folder.name}</div>
          <div className="mono" style={{ fontSize: 10, color: "var(--faint)" }}>{folder.files} fichier(s){folder.subfolders ? ` · ${folder.subfolders} dossier(s)` : ""}{ownerDev ? ` · → ${ownerDev.tag || ownerDev.name}` : ""}</div>
        </div>
      </div>
      {canEdit && !isPhone && <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
        <button onClick={onRename} title="Renommer" style={{ ...miniBtn, width: "auto", padding: "0 9px", gap: 5 }}><span style={{ fontSize: 11 }}>Renommer</span></button>
        <button onClick={onMove} title="Déplacer (vers un iPhone ou un dossier)" style={{ ...miniBtn, width: "auto", padding: "0 9px", gap: 5 }}>{React.createElement(Icon.send, { size: 12 })}<span style={{ fontSize: 11 }}>Déplacer</span></button>
        <button onClick={onDelete} title="Supprimer" style={{ ...miniBtn, marginLeft: "auto" }}>{React.createElement(Icon.x, { size: 12 })}</button>
      </div>}
    </div>
  );
}
const miniBtn = { height: 28, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: 7, background: "var(--surface-3)", border: "1px solid var(--border)", color: "var(--muted)", cursor: "pointer", flexShrink: 0, width: 28 };

// ---- Tuile média ----
function MediaTile({ fileUrl, f, onOpen, onPush, onDelete, pushing, canPush }) {
  const isImg = f.kind === "image";
  return (
    <div style={{ border: "1px solid var(--border)", borderRadius: 11, overflow: "hidden", background: "var(--surface-2)" }}>
      <div onClick={() => onOpen(f)} title="Aperçu" style={{ cursor: "pointer", aspectRatio: "1", background: "#0b1020", display: "grid", placeItems: "center", overflow: "hidden", position: "relative" }}>
        {isImg ? <img src={fileUrl} alt={f.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} /> : React.createElement(Icon.play, { size: 26, color: "var(--muted)" })}
        <div style={{ position: "absolute", top: 6, right: 6, padding: "2px 6px", borderRadius: 6, background: "rgba(4,7,15,.6)", color: "#fff", fontSize: 9.5 }}>{isImg ? "photo" : "vidéo"}</div>
      </div>
      <div style={{ padding: "7px 8px" }}>
        <div style={{ fontSize: 11.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }} title={f.name}>{f.name}</div>
        <div className="mono" style={{ fontSize: 9.5, color: "var(--faint)", marginBottom: 6 }}>{fmtSize(f.size)}</div>
        <div style={{ display: "flex", gap: 5 }}>
          {canPush && <button onClick={() => onPush(f.name)} disabled={pushing === f.name} style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "6px", borderRadius: 7, background: "var(--accent-soft)", border: "1px solid var(--accent-line)", color: "var(--accent)", fontSize: 11, fontWeight: 600, cursor: "pointer" }}>
            {React.createElement(Icon.send, { size: 12 })}{pushing === f.name ? "…" : "Envoyer"}
          </button>}
          {onDelete && <button onClick={() => onDelete(f.name)} title="Supprimer" style={{ width: 28, display: "grid", placeItems: "center", borderRadius: 7, background: "var(--surface-3)", border: "1px solid var(--border)", color: "var(--faint)", cursor: "pointer" }}>{React.createElement(Icon.x, { size: 12 })}</button>}
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Navigateur réutilisé (admin + opérateur)
//  - scopeUdid + deviceTag : on navigue DANS le dossier de cet iPhone (Téléphones/<nom>)
//  - sinon : bibliothèque complète (racine)
// ============================================================
function LibraryView({ canEdit, scopeUdid, deviceTag, pushUdid, devices, cols = 4 }) {
  const { useState, useEffect, useRef } = React;
  const [base, setBase] = useState(scopeUdid ? null : "");   // null = en cours de résolution (scope)
  const [trail, setTrail] = useState([]);                     // [{name, path}] chemins absolus
  const [root, setRoot] = useState("");
  const [owner, setOwner] = useState(null);
  const [folders, setFolders] = useState([]);
  const [files, setFiles] = useState([]);
  const [loading, setLoading] = useState(false);
  const [toast, setToast] = useState("");
  const [pushing, setPushing] = useState(null);
  const [preview, setPreview] = useState(null);
  const [busy, setBusy] = useState(false);
  const [moveItem, setMoveItem] = useState(null);
  const fileRef = useRef(null);
  const flash = (t) => { setToast(t); setTimeout(() => setToast(""), 2800); };

  // résout le dossier de base (dossier du tel pour la vue iPhone)
  useEffect(() => {
    let on = true;
    (async () => {
      if (scopeUdid) {
        setBase(null); setTrail([]);
        const r = await window.Backend.libPhone(scopeUdid, deviceTag || "");
        if (on) setBase(r && r.path ? r.path : "");
      } else { setBase(""); setTrail([]); }
    })();
    return () => { on = false; };
  }, [scopeUdid, deviceTag]);

  const path = trail.length ? trail[trail.length - 1].path : (base || "");
  const effUdid = pushUdid || scopeUdid || owner || null;
  const canPush = !!effUdid;

  const reload = async () => {
    if (base === null) return;                  // dossier du tel pas encore résolu
    setLoading(true);
    const b = await window.Backend.libBrowse(path);
    if (b) { setFolders(b.folders); setFiles(b.files); setRoot(b.root); setOwner(b.owner || null); }
    setLoading(false);
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [path, base]);

  const openFolder = (f) => setTrail([...trail, { name: f.name, path: f.path }]);
  const goCrumb = (i) => setTrail(i < 0 ? [] : trail.slice(0, i + 1));

  const newFolder = async () => {
    const name = window.prompt("Nom du nouveau dossier :"); if (!name) return;
    const r = await window.Backend.libMkdir(name, path); if (r && r.ok) { flash("Dossier créé"); reload(); } else flash((r && r.error) || "Échec");
  };
  const onPick = async (e) => {
    const fs = [...e.target.files]; if (!fs.length) return;
    setBusy(true);
    for (const f of fs) await window.Backend.libUpload(path, f);
    setBusy(false); flash(`${fs.length} fichier(s) ajouté(s)`); reload(); e.target.value = "";
  };
  const rename = async (folder) => {
    const name = window.prompt("Nouveau nom du dossier :", folder.name); if (!name || name === folder.name) return;
    const r = await window.Backend.libRename(folder.path, name);
    if (r && r.status === 200) { flash("Renommé"); reload(); } else flash((r && r.error) || "Échec du renommage");
  };
  const doMove = async (dest) => {
    const r = await window.Backend.libMove(moveItem.path, dest); setMoveItem(null);
    if (r && r.status === 200) { flash("Déplacé"); reload(); } else flash((r && r.error) || "Échec du déplacement");
  };
  const delFolder = async (folder) => { if (!window.confirm(`Supprimer le dossier « ${folder.name} » et tout son contenu ?`)) return; await window.Backend.libDelFolder(folder.path); flash("Dossier supprimé"); reload(); };
  const delFile = async (name) => { await window.Backend.libDelFile((path ? path + "/" : "") + name); reload(); };
  const push = async (name) => {
    if (!effUdid) { flash("Place ce dossier dans un iPhone (Déplacer) pour pouvoir envoyer."); return; }
    setPushing(name);
    const r = await window.Backend.libPush(path, name, effUdid); setPushing(null);
    const ok = r && r.result && r.result.StatusCode === 200;
    flash(ok ? "Envoyé au téléphone ✓" : "Échec de l'envoi"); if (ok) setPreview(null);
  };

  const rootLabel = scopeUdid ? "Dossier du téléphone" : "Bibliothèque";

  return (
    <div>
      {root && <div className="mono" style={{ fontSize: 10.5, color: "var(--faint)", marginBottom: 8, display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
        {React.createElement(Icon.grid, { size: 11 })}<span>Emplacement disque :</span><span style={{ color: "var(--muted)" }}>{root}</span>
      </div>}

      <div style={{ display: "flex", alignItems: "center", flexWrap: "wrap", gap: 4, marginBottom: 10, fontSize: 12 }}>
        <button onClick={() => goCrumb(-1)} style={{ display: "flex", alignItems: "center", gap: 5, padding: "4px 8px", borderRadius: 7, background: !trail.length ? "var(--accent-soft)" : "var(--surface-2)", border: "1px solid " + (!trail.length ? "var(--accent-line)" : "var(--border)"), color: !trail.length ? "var(--accent)" : "var(--muted)", cursor: "pointer", fontWeight: 600 }}>
          {React.createElement(scopeUdid ? Icon.phone : Icon.grid, { size: 12 })} {rootLabel}
        </button>
        {trail.map((c, i) => (
          <React.Fragment key={c.path}>
            <span style={{ color: "var(--faint)" }}>›</span>
            <button onClick={() => goCrumb(i)} style={{ padding: "4px 8px", borderRadius: 7, background: i === trail.length - 1 ? "var(--accent-soft)" : "var(--surface-2)", border: "1px solid " + (i === trail.length - 1 ? "var(--accent-line)" : "var(--border)"), color: i === trail.length - 1 ? "var(--accent)" : "var(--muted)", cursor: "pointer", fontWeight: 600 }}>{c.name}</button>
          </React.Fragment>
        ))}
      </div>

      {canEdit && <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 12, flexWrap: "wrap" }}>
        <input ref={fileRef} type="file" accept="image/*,video/*" multiple style={{ display: "none" }} onChange={onPick} />
        <Button variant="ghost" icon="plus" onClick={newFolder}>Nouveau dossier</Button>
        <Button variant="primary" icon="plus" onClick={() => fileRef.current && fileRef.current.click()}>{busy ? "Upload…" : "Ajouter des fichiers"}</Button>
        <span className="mono" style={{ fontSize: 11, color: "var(--faint)" }}>{folders.length} dossier(s) · {files.length} fichier(s)</span>
      </div>}

      {toast && <div style={{ marginBottom: 10, padding: "8px 11px", borderRadius: 8, background: "var(--accent-soft)", border: "1px solid var(--accent-line)", color: "var(--accent)", fontSize: 12 }}>{toast}</div>}

      {folders.length > 0 && <div style={{ display: "grid", gridTemplateColumns: `repeat(${Math.max(1, Math.min(cols, 3))}, 1fr)`, gap: 9, marginBottom: 12 }}>
        {folders.map(fd => <FolderTile key={fd.path} folder={fd} canEdit={canEdit} devices={devices}
          onOpen={() => openFolder(fd)} onRename={() => rename(fd)} onMove={() => setMoveItem(fd)} onDelete={() => delFolder(fd)} />)}
      </div>}

      {files.length === 0 && folders.length === 0
        ? <div style={{ color: "var(--faint)", fontSize: 12.5, padding: "14px 0", textAlign: "center" }}>
            {(loading || base === null) ? "Chargement…" : (canEdit ? "Vide — créez un dossier ou ajoutez des fichiers." : "Aucun média ici.")}
          </div>
        : files.length > 0 && <div style={{ display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: 9 }}>
            {files.map(f => <MediaTile key={f.name} fileUrl={window.Backend.libFileUrl((path ? path + "/" : "") + f.name)} f={f}
              onOpen={setPreview} onPush={push} onDelete={canEdit ? delFile : null} pushing={pushing} canPush={canPush} />)}
          </div>}

      <PreviewModal fileUrl={preview ? window.Backend.libFileUrl((path ? path + "/" : "") + preview.name) : ""} f={preview} onClose={() => setPreview(null)} onPush={push} pushing={pushing} canPush={canPush} />
      {moveItem && <MoveModal item={moveItem} onClose={() => setMoveItem(null)} onMove={doMove} />}
    </div>
  );
}

// Carte "Médias" côté opérateur : le dossier de SON iPhone, envoi 1 clic.
function MediaCard({ device }) {
  if (!device || !device.udid) return null;
  return (
    <RemoteCard title={window.t ? t("medias") : "Médias"} icon="image" collapsible startOpen={false}>
      <LibraryView canEdit={true} scopeUdid={device.udid} deviceTag={device.tag} pushUdid={device.udid} cols={2} />
    </RemoteCard>
  );
}

// Page "Dossiers" admin : bibliothèque centrale + dossier auto par iPhone.
function AdminFolders() {
  const { useState, useEffect } = React;
  const farm = useLiveDevices();
  const isLive = farm.online;
  const devices = (isLive && farm.list) ? farm.list : [];
  const [scope, setScope] = useState(null);   // null = bibliothèque (tout), sinon udid d'un iPhone

  // garantit le dossier auto de chaque iPhone (au nom affiché) -> ils apparaissent sous "Téléphones"
  useEffect(() => {
    devices.forEach(d => { if (d.udid) window.Backend.libPhone(d.udid, d.tag); });
    /* eslint-disable-next-line */
  }, [devices.map(d => d.udid + ":" + d.tag).join(",")]);

  if (!isLive) return (
    <div>
      <PageHead title="Dossiers" sub="parc non synchronisé" />
      <SyncNotice online={false} ready={farm.ready} variant="admin" onSync={farm.refresh} />
    </div>
  );
  const cur = devices.find(d => (d.udid || d.id) === scope);
  return (
    <div>
      <PageHead title="Dossiers" sub="● LIVE · bibliothèque centrale + 1 dossier auto par iPhone (Téléphones/) — le contenu d'un tel va dans son dossier" />
      <div style={{ display: "grid", gridTemplateColumns: "260px 1fr", gap: 16 }} className="ov-grid">
        <div style={{ display: "grid", gap: 6, alignContent: "start" }}>
          <button onClick={() => setScope(null)} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 12px", borderRadius: 10, textAlign: "left",
            background: !scope ? "var(--accent-soft)" : "var(--surface-2)", border: "1px solid " + (!scope ? "var(--accent-line)" : "var(--border)"), cursor: "pointer" }}>
            {React.createElement(Icon.grid, { size: 16, color: !scope ? "var(--accent)" : "var(--muted)" })}
            <div style={{ flex: 1, fontSize: 13, fontWeight: 700 }}>Bibliothèque (tout)</div>
          </button>
          <div className="mono" style={{ fontSize: 10, color: "var(--faint)", margin: "6px 2px 2px" }}>DOSSIER PAR IPHONE</div>
          {devices.map(d => (
            <button key={d.id} onClick={() => setScope(d.udid || d.id)} style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 12px", borderRadius: 10, textAlign: "left",
              background: scope === (d.udid || d.id) ? "var(--accent-soft)" : "var(--surface-2)", border: "1px solid " + (scope === (d.udid || d.id) ? "var(--accent-line)" : "var(--border)"), cursor: "pointer" }}>
              {React.createElement(Icon.phone, { size: 16, color: "var(--muted)" })}
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>{d.tag}</div>
                <div className="mono" style={{ fontSize: 10, color: "var(--faint)" }}>{d.pool || d.name}</div>
              </div>
              <StatusDot status={d.status} />
            </button>
          ))}
        </div>
        <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--r-lg)", padding: 18 }}>
          <div style={{ fontSize: 15, fontWeight: 700, marginBottom: 14 }}>{cur ? `Dossier de ${cur.tag}` : "Bibliothèque centrale"}</div>
          <LibraryView canEdit={true} scopeUdid={scope || null} deviceTag={cur ? cur.tag : null} pushUdid={null} devices={devices} cols={4} />
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { LibraryView, MediaCard, AdminFolders });
