/* ═══════════════════════════════════════════════════════════
   DrewFans — Components
   - Icons (inline SVG, no library)
   - AgeGate (splash with cookie persistence)
   - Header / MobileNav
   - VideoCard (tap-to-preview on mobile, hover-to-preview on desktop)
   - ModelCard, CategoryCard
   - CustomPlayer (scrubbing thumbs + skip 10s + download + shortcuts)
   - Pagination, Toast
   ═══════════════════════════════════════════════════════════ */

const { useState, useEffect, useRef, useCallback, useMemo } = React;

/* ─── Icons ─────────────────────────────────────────────── */
const Icon = {
  Search: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>),
  Bookmark: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill={p.filled ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z"/></svg>),
  Eye: (p = {}) => (<svg width={p.size || 14} height={p.size || 14} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></svg>),
  Clock: (p = {}) => (<svg width={p.size || 14} height={p.size || 14} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12,6 12,12 16,14"/></svg>),
  Play: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>),
  Pause: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>),
  Volume: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="11,5 6,9 2,9 2,15 6,15 11,19"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></svg>),
  VolumeOff: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="11,5 6,9 2,9 2,15 6,15 11,19"/><line x1="23" y1="9" x2="17" y2="15"/><line x1="17" y1="9" x2="23" y2="15"/></svg>),
  Maximize: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>),
  Heart: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill={p.filled ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>),
  Download: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>),
  Share: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>),
  Sliders: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg>),
  Menu: (p = {}) => (<svg width={p.size || 18} height={p.size || 18} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>),
  Close: (p = {}) => (<svg width={p.size || 18} height={p.size || 18} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>),
  ChevronDown: (p = {}) => (<svg width={p.size || 12} height={p.size || 12} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>),
  ArrowLeft: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m12 19-7-7 7-7"/><path d="M19 12H5"/></svg>),
  Home: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9,22 9,12 15,12 15,22"/></svg>),
  User: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>),
  Grid: (p = {}) => (<svg width={p.size || 16} height={p.size || 16} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>),
  // Skip ±10s — circular arrow with "10"
  Skip10: (p = {}) => (<svg width={p.size || 20} height={p.size || 20} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12a9 9 0 1 1-9-9c2.5 0 4.8 1 6.4 2.6L21 8"/><polyline points="21 3 21 8 16 8"/><text x="12" y="15.5" fontSize="7" fill="currentColor" stroke="none" textAnchor="middle" fontFamily="ui-monospace, monospace" fontWeight="700">10</text></svg>),
  Back10: (p = {}) => (<svg width={p.size || 20} height={p.size || 20} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 9-9c-2.5 0-4.8 1-6.4 2.6L3 8"/><polyline points="3 3 3 8 8 8"/><text x="12" y="15.5" fontSize="7" fill="currentColor" stroke="none" textAnchor="middle" fontFamily="ui-monospace, monospace" fontWeight="700">10</text></svg>),
};

/* ─── Utility ───────────────────────────────────────────── */
function formatTime(seconds) {
  if (!isFinite(seconds) || seconds < 0) return '0:00';
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = Math.floor(seconds % 60);
  if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
  return `${m}:${String(s).padStart(2, '0')}`;
}

function setCookie(name, value, days) {
  const exp = new Date(Date.now() + days * 86400000).toUTCString();
  document.cookie = `${name}=${encodeURIComponent(value)}; expires=${exp}; path=/; SameSite=Lax`;
}
function getCookie(name) {
  const m = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
  return m ? decodeURIComponent(m[2]) : null;
}

function useMediaQuery(query) {
  const [matches, setMatches] = useState(() => typeof window !== 'undefined' && window.matchMedia(query).matches);
  useEffect(() => {
    const m = window.matchMedia(query);
    const h = (e) => setMatches(e.matches);
    m.addEventListener('change', h);
    setMatches(m.matches);
    return () => m.removeEventListener('change', h);
  }, [query]);
  return matches;
}

/* ─── Age Gate ──────────────────────────────────────────── */
function AgeGate({ onAccept }) {
  return (
    <div className="age-gate">
      <div className="age-gate-card">
        <div className="age-gate-logo">drew<b>fans</b>.</div>
        <h1 className="age-gate-h1">Solo per adulti.</h1>
        <p className="age-gate-p">
          Questo sito contiene materiale per un pubblico adulto. Per continuare devi confermare di
          avere almeno 18 anni e che la legge del tuo paese permette la visione di questi contenuti.
        </p>
        <div className="age-gate-actions">
          <button
            className="age-gate-btn primary"
            onClick={onAccept}
          >Sì, ho 18+ — Entra</button>
          <button
            className="age-gate-btn"
            onClick={() => { window.location.href = 'https://www.google.com'; }}
          >Esci</button>
        </div>
        <div className="age-gate-foot">
          Cliccando "Entra" confermi sotto la tua responsabilità di essere maggiorenne. La scelta
          viene ricordata per 30 giorni.
        </div>
      </div>
    </div>
  );
}

/* ─── Watch Later (localStorage) ────────────────────────── */
function useWatchLater() {
  const [items, setItems] = useState(() => {
    try { return JSON.parse(localStorage.getItem('df_watch_later') || '[]'); } catch { return []; }
  });
  useEffect(() => {
    localStorage.setItem('df_watch_later', JSON.stringify(items));
  }, [items]);
  return {
    items,
    add: (v) => setItems(prev => prev.some(x => x.url === v.url) ? prev : [v, ...prev]),
    remove: (url) => setItems(prev => prev.filter(x => x.url !== url)),
    has: (url) => items.some(x => x.url === url),
    toggle: (v) => setItems(prev => prev.some(x => x.url === v.url) ? prev.filter(x => x.url !== v.url) : [v, ...prev]),
  };
}

/* ─── Toast ─────────────────────────────────────────────── */
function useToast() {
  const [toast, setToast] = useState(null);
  const ref = useRef(null);
  const show = useCallback((msg) => {
    setToast(msg);
    if (ref.current) clearTimeout(ref.current);
    ref.current = setTimeout(() => setToast(null), 2500);
  }, []);
  return { toast, show };
}

function ToastView({ message }) {
  if (!message) return null;
  return <div className="df-toast">{message}</div>;
}

/* ─── Header ────────────────────────────────────────────── */
function Header({ route, onNav, search, setSearch, onSubmitSearch, watchLaterCount }) {
  const [mobileOpen, setMobileOpen] = useState(false);
  const isMobile = useMediaQuery('(max-width: 768px)');

  useEffect(() => { setMobileOpen(false); }, [route]);

  const NavLinks = ({ mobile }) => {
    const Btn = (id, icon, label, badge) => {
      const cls = mobile ? 'df-mobile-nav-btn' : 'df-nav-btn';
      return (
        <button
          key={id}
          className={`${cls} ${route === id ? 'active' : ''}`}
          onClick={() => onNav(id)}
        >
          {icon}
          <span>{label}</span>
          {badge ? <span className="df-nav-badge">{badge}</span> : null}
        </button>
      );
    };
    return (
      <>
        {Btn('home', <Icon.Home/>, 'Video')}
        {Btn('pornstars', <Icon.User/>, 'Pornstar')}
        {Btn('categories', <Icon.Grid/>, 'Categorie')}
        {Btn('watchlater', <Icon.Bookmark/>, 'Guarda dopo', watchLaterCount > 0 ? watchLaterCount : null)}
      </>
    );
  };

  return (
    <>
      <header className="df-header">
        <div className="df-logo" onClick={() => onNav('home')}>drew<b>fans</b>.</div>

        {!isMobile && <nav className="df-nav"><NavLinks/></nav>}

        <form
          className="df-search"
          onSubmit={(e) => { e.preventDefault(); onSubmitSearch(); }}
        >
          <span className="df-search-ico"><Icon.Search size={14}/></span>
          <input
            className="df-search-input"
            type="text"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder="Cerca video o pornstar..."
            aria-label="Cerca"
          />
        </form>

        {isMobile && (
          <button
            className="df-icon-btn df-menu-toggle"
            onClick={() => setMobileOpen(true)}
            aria-label="Menu"
          ><Icon.Menu/></button>
        )}
      </header>

      {/* Mobile drawer */}
      <div
        className={`df-mobile-overlay ${mobileOpen ? 'open' : ''}`}
        onClick={() => setMobileOpen(false)}
      />
      <aside className={`df-mobile-nav ${mobileOpen ? 'open' : ''}`}>
        <button
          className="df-mobile-nav-close"
          onClick={() => setMobileOpen(false)}
          aria-label="Chiudi menu"
        ><Icon.Close/></button>
        <NavLinks mobile/>
      </aside>
    </>
  );
}

/* ─── Video Card ────────────────────────────────────────────
   Behavior:
   - Desktop: 300ms hover → preview overlay
   - Mobile: 1st tap on thumb → preview starts (with "tocca
     per guardare" hint); 2nd tap on thumb → open video.
     Tap on title/meta area → open video directly.
     Preview auto-stops after 6s of inactivity. */
function VideoCard({ video, onClick, onModelClick, watchLater }) {
  const thumbSrc = video.thumbnailWebp || video.thumbnail;
  const thumb = api.proxyUrl(thumbSrc);
  const previewSrc = video.preview ? api.proxyUrl(video.preview) : '';
  const modelName = video.models?.[0]?.name || '';
  const modelUrl = video.models?.[0]?.url || '';
  const isSaved = watchLater.has(video.url);
  const tag = video.tag || (video.categories?.[0]) || null;

  const isMobile = useMediaQuery('(max-width: 768px)');
  const [showPreview, setShowPreview] = useState(false);
  const [previewPrimed, setPreviewPrimed] = useState(false); // mobile: 1 tap shown
  const hoverTimer = useRef(null);
  const previewTimer = useRef(null);

  // Desktop hover
  const onMouseEnter = () => {
    if (isMobile || !previewSrc) return;
    if (hoverTimer.current) clearTimeout(hoverTimer.current);
    hoverTimer.current = setTimeout(() => setShowPreview(true), 300);
  };
  const onMouseLeave = () => {
    if (isMobile) return;
    if (hoverTimer.current) clearTimeout(hoverTimer.current);
    setShowPreview(false);
  };

  // Mobile tap-to-preview
  const onThumbTap = (e) => {
    if (!isMobile) {
      onClick(video);
      return;
    }
    if (!previewSrc) {
      onClick(video);
      return;
    }
    if (!previewPrimed) {
      // First tap: start preview
      e.stopPropagation();
      setShowPreview(true);
      setPreviewPrimed(true);
      if (previewTimer.current) clearTimeout(previewTimer.current);
      previewTimer.current = setTimeout(() => {
        setShowPreview(false);
        setPreviewPrimed(false);
      }, 6000);
    } else {
      // Second tap: open video
      onClick(video);
    }
  };

  useEffect(() => {
    return () => {
      if (hoverTimer.current) clearTimeout(hoverTimer.current);
      if (previewTimer.current) clearTimeout(previewTimer.current);
    };
  }, []);

  // Reset primed state when card scrolls off — also helps when user scrolls away
  useEffect(() => {
    if (!isMobile || !previewPrimed) return;
    const reset = () => {
      setShowPreview(false);
      setPreviewPrimed(false);
      if (previewTimer.current) clearTimeout(previewTimer.current);
    };
    document.addEventListener('scroll', reset, { passive: true, once: true });
    return () => document.removeEventListener('scroll', reset);
  }, [isMobile, previewPrimed]);

  const handleInfoClick = (e) => {
    e.stopPropagation();
    // Model name click — go to actress page
    if (e.target.closest('.df-card-model')) return;
    onClick(video);
  };

  return (
    <div className="df-card" onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
      <div className="df-thumb" onClick={onThumbTap}>
        {thumb && <img src={thumb} alt={video.title} loading="lazy" />}
        {showPreview && previewSrc && (
          <video
            src={previewSrc}
            muted
            playsInline
            loop
            autoPlay
          />
        )}
        <div className="df-thumb-fade"/>
        {tag && <div className="df-thumb-tag">{tag}</div>}
        {isMobile && showPreview && (
          <div className="df-thumb-preview-ind">Tocca per guardare</div>
        )}
        <button
          className={`df-thumb-wl ${isSaved ? 'saved' : ''}`}
          onClick={(e) => {
            e.stopPropagation();
            watchLater.toggle({
              url: video.url, title: video.title,
              thumbnail: video.thumbnail, thumbnailWebp: video.thumbnailWebp,
              preview: video.preview, duration: video.duration,
              models: video.models, views: video.views, timeAgo: video.timeAgo,
            });
          }}
          aria-label={isSaved ? 'Rimuovi da Guarda dopo' : 'Salva in Guarda dopo'}
          title={isSaved ? 'Rimuovi da Guarda dopo' : 'Salva in Guarda dopo'}
        >
          <Icon.Bookmark size={14} filled={isSaved}/>
        </button>
        {video.duration && <div className="df-thumb-duration">{video.duration}</div>}
      </div>
      <div className="df-card-info" onClick={handleInfoClick}>
        <div className="df-card-title">{video.title}</div>
        <div className="df-card-meta">
          {modelName && (
            <span
              className="df-card-model"
              onClick={(e) => { e.stopPropagation(); onModelClick(modelUrl, modelName); }}
            >{modelName}</span>
          )}
          {modelName && <span className="df-card-meta-sep">·</span>}
          {video.views && (
            <span className="df-card-meta-stat"><Icon.Eye size={11}/> {video.views}</span>
          )}
          {video.timeAgo && (
            <>
              <span className="df-card-meta-sep">·</span>
              <span className="df-card-meta-stat">{video.timeAgo}</span>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

function VideoGrid({ videos, onVideoClick, onModelClick, watchLater, emptyText }) {
  if (!videos || videos.length === 0) {
    return (
      <div className="df-empty">
        <div className="df-empty-h">{emptyText || 'Nessun video trovato'}</div>
        <div className="df-empty-p">Prova a cambiare filtro o periodo.</div>
      </div>
    );
  }
  return (
    <div className="df-grid">
      {videos.map((v, i) => (
        <VideoCard
          key={v.url || i}
          video={v}
          onClick={onVideoClick}
          onModelClick={onModelClick}
          watchLater={watchLater}
        />
      ))}
    </div>
  );
}

/* ─── Model Card / Grid ─────────────────────────────────── */
function ModelCard({ model, onModelClick }) {
  const photo = model.photo ? api.proxyUrl(model.photo) : '';
  const name = model.name || 'Pornstar';
  const initials = name.split(/\s+/).map(s => s[0]).join('').slice(0, 2).toUpperCase();
  return (
    <div className="df-card df-model-card" onClick={() => onModelClick(model.url, name)}>
      <div className="df-thumb">
        {photo
          ? <img src={photo} alt={name} loading="lazy"/>
          : <div className="df-model-placeholder">{initials}</div>
        }
      </div>
      <div className="df-card-info">
        <div className="df-card-title">{name}</div>
        {(model.videos || model.views) && (
          <div className="df-card-meta" style={{ justifyContent: 'center', marginTop: 4 }}>
            {model.videos != null && <span className="df-card-meta-stat">{model.videos} video</span>}
            {model.videos != null && model.views && <span className="df-card-meta-sep">·</span>}
            {model.views && <span className="df-card-meta-stat">{model.views} views</span>}
          </div>
        )}
      </div>
    </div>
  );
}

function ModelGrid({ models, onModelClick }) {
  if (!models || models.length === 0) return null;
  return (
    <div className="df-grid">
      {models.map((m, i) => <ModelCard key={m.url || i} model={m} onModelClick={onModelClick}/>)}
    </div>
  );
}

/* ─── Category Card / Grid ──────────────────────────────── */
function CategoryCard({ category, onClick }) {
  return (
    <div className="df-cat-card" onClick={() => onClick(category)}>
      <div className="df-cat-name">{category.name}</div>
      <div className="df-cat-meta">
        {category.count != null
          ? `${category.count.toLocaleString('it-IT')} video`
          : 'Esplora'}
      </div>
    </div>
  );
}

/* ─── Pagination ────────────────────────────────────────── */
function Pagination({ page, onChange, hasNext = true }) {
  const pages = useMemo(() => {
    // Window of ±2 pages around current
    const start = Math.max(1, page - 2);
    const end = page + 2;
    const arr = [];
    for (let p = start; p <= end; p++) arr.push(p);
    return arr;
  }, [page]);

  return (
    <div className="df-pagination">
      <button
        className="df-page-btn"
        disabled={page <= 1}
        onClick={() => onChange(page - 1)}
      >‹ Precedente</button>
      {page > 3 && (
        <>
          <button className="df-page-btn" onClick={() => onChange(1)}>1</button>
          <span style={{ alignSelf: 'center', color: 'var(--text-mute)' }}>…</span>
        </>
      )}
      {pages.map(p => (
        <button
          key={p}
          className={`df-page-btn ${p === page ? 'active' : ''}`}
          onClick={() => onChange(p)}
        >{p}</button>
      ))}
      <button
        className="df-page-btn"
        disabled={!hasNext}
        onClick={() => onChange(page + 1)}
      >Successiva ›</button>
    </div>
  );
}

/* ─── Custom Video Player ───────────────────────────────────
   Features:
   - Scrubbing thumbs on hover (uses timeline_screens_url from API)
   - Skip ±10s buttons
   - Quality menu
   - Download (opens current stream in new tab)
   - Keyboard: Space, ←, →, M, F, ↑, ↓
   - Resume position via localStorage (per video)
   - Buffering indicator */
function CustomPlayer({ data }) {
  const { streams = [], preview, title } = data || {};
  const videoId = data?.id || data?.title || 'unknown';
  const resumeKey = `df_resume_${videoId}`;

  const videoRef = useRef(null);
  const wrapRef = useRef(null);
  const scrubRef = useRef(null);
  const [playing, setPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [buffered, setBuffered] = useState(0);
  const [muted, setMuted] = useState(false);
  const [volume, setVolume] = useState(1);
  const [buffering, setBuffering] = useState(false);
  const [showControls, setShowControls] = useState(true);
  const [qualityMenuOpen, setQualityMenuOpen] = useState(false);
  const [selectedQuality, setSelectedQuality] = useState(0);
  const [scrubHover, setScrubHover] = useState(null); // { x, t } | null
  const [keyHint, setKeyHint] = useState(null);
  const controlsTimeoutRef = useRef(null);
  const keyHintTimerRef = useRef(null);

  // Pick initial quality from localStorage preference (best <= preferred), default highest
  useEffect(() => {
    if (!streams.length) return;
    const preferred = localStorage.getItem('df_preferred_quality') || '1080p';
    const idx = streams.findIndex(s => s.quality === preferred);
    setSelectedQuality(idx !== -1 ? idx : streams.length - 1);
  }, [streams.length]);

  const currentStream = streams[selectedQuality] || streams[0];
  const currentSrc = currentStream && data?.originalUrl
    ? api.streamUrl(data.originalUrl, currentStream.quality)
    : '';

  // Timeline scrubbing thumbnails — derived from API response
  const tlUrl = data?.timeline_screens_url || '';
  const tlInterval = parseInt(data?.timeline_screens_interval || 10);
  const tlCount = parseInt(data?.timeline_screens_count || 0);
  const hasScrubThumbs = !!(tlUrl && tlInterval > 0 && tlCount > 0);

  function getThumbUrl(seconds) {
    if (!hasScrubThumbs) return '';
    const total = tlCount * tlInterval;
    const t = Math.max(tlInterval, Math.min(total, Math.ceil(seconds / tlInterval) * tlInterval));
    return api.proxyUrl(tlUrl.replace('{time}', String(t)));
  }

  // Video element event wiring
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    const onTime = () => setCurrentTime(v.currentTime);
    const onDur = () => setDuration(v.duration || 0);
    const onEnd = () => setPlaying(false);
    const onWaiting = () => setBuffering(true);
    const onCanPlay = () => setBuffering(false);
    const onPlaying = () => { setBuffering(false); setPlaying(true); };
    const onPause = () => setPlaying(false);
    const onProgress = () => {
      try {
        if (v.buffered.length > 0) {
          setBuffered(v.buffered.end(v.buffered.length - 1));
        }
      } catch {}
    };
    const onVolume = () => { setMuted(v.muted); setVolume(v.volume); };
    const onLoaded = () => {
      // Resume if we have a saved position
      try {
        const saved = parseFloat(localStorage.getItem(resumeKey) || '0');
        if (saved > 5 && saved < (v.duration || 0) - 5) {
          v.currentTime = saved;
        }
      } catch {}
    };

    v.addEventListener('timeupdate', onTime);
    v.addEventListener('loadedmetadata', onDur);
    v.addEventListener('loadeddata', onLoaded);
    v.addEventListener('ended', onEnd);
    v.addEventListener('waiting', onWaiting);
    v.addEventListener('canplay', onCanPlay);
    v.addEventListener('playing', onPlaying);
    v.addEventListener('pause', onPause);
    v.addEventListener('progress', onProgress);
    v.addEventListener('volumechange', onVolume);
    return () => {
      v.removeEventListener('timeupdate', onTime);
      v.removeEventListener('loadedmetadata', onDur);
      v.removeEventListener('loadeddata', onLoaded);
      v.removeEventListener('ended', onEnd);
      v.removeEventListener('waiting', onWaiting);
      v.removeEventListener('canplay', onCanPlay);
      v.removeEventListener('playing', onPlaying);
      v.removeEventListener('pause', onPause);
      v.removeEventListener('progress', onProgress);
      v.removeEventListener('volumechange', onVolume);
    };
  }, [currentSrc, resumeKey]);

  // Save resume position periodically (every 5s)
  useEffect(() => {
    if (!playing) return;
    const it = setInterval(() => {
      const v = videoRef.current;
      if (v && v.currentTime > 5) {
        localStorage.setItem(resumeKey, String(v.currentTime));
      }
    }, 5000);
    return () => clearInterval(it);
  }, [playing, resumeKey]);

  // Auto-hide controls
  const wakeControls = useCallback(() => {
    setShowControls(true);
    if (controlsTimeoutRef.current) clearTimeout(controlsTimeoutRef.current);
    if (playing) {
      controlsTimeoutRef.current = setTimeout(() => setShowControls(false), 3000);
    }
  }, [playing]);
  useEffect(() => {
    wakeControls();
    return () => { if (controlsTimeoutRef.current) clearTimeout(controlsTimeoutRef.current); };
  }, [playing, wakeControls]);

  /* ── Actions ── */
  const togglePlay = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    if (v.paused) v.play().catch(() => {});
    else v.pause();
  }, []);

  const seekTo = useCallback((t) => {
    const v = videoRef.current;
    if (!v) return;
    v.currentTime = Math.max(0, Math.min(v.duration || 0, t));
  }, []);

  const skip = useCallback((delta) => {
    const v = videoRef.current;
    if (!v) return;
    v.currentTime = Math.max(0, Math.min(v.duration || 0, v.currentTime + delta));
    showKeyHint(delta > 0 ? '+10s' : '−10s');
  }, []);

  const setVol = useCallback((delta) => {
    const v = videoRef.current;
    if (!v) return;
    v.volume = Math.max(0, Math.min(1, v.volume + delta));
    showKeyHint(`Volume ${Math.round(v.volume * 100)}%`);
  }, []);

  const toggleMute = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    v.muted = !v.muted;
    showKeyHint(v.muted ? 'Muto' : 'Audio attivo');
  }, []);

  const toggleFullscreen = useCallback(() => {
    const v = videoRef.current;
    const wrap = wrapRef.current;
    // iOS (iPhone/iPad): use native video fullscreen player
    if (v && v.webkitEnterFullscreen) {
      v.webkitEnterFullscreen();
      return;
    }
    if (!wrap) return;
    if (!document.fullscreenElement) {
      (wrap.requestFullscreen || wrap.webkitRequestFullscreen || (() => {})).call(wrap);
    } else {
      (document.exitFullscreen || document.webkitExitFullscreen || (() => {})).call(document);
    }
  }, []);

  const onDownload = useCallback(() => {
    if (!currentStream || !data?.originalUrl) return;
    const url = api.streamUrl(data.originalUrl, currentStream.quality);
    const a = document.createElement('a');
    a.href = url;
    a.download = (title || 'video') + '.mp4';
    a.target = '_blank';
    a.rel = 'noopener';
    document.body.appendChild(a);
    a.click();
    a.remove();
  }, [currentStream, title]);

  function showKeyHint(text) {
    setKeyHint(text);
    if (keyHintTimerRef.current) clearTimeout(keyHintTimerRef.current);
    keyHintTimerRef.current = setTimeout(() => setKeyHint(null), 700);
  }

  // Quality change — preserve position + playing state
  const changeQuality = (idx) => {
    if (idx === selectedQuality) { setQualityMenuOpen(false); return; }
    const v = videoRef.current;
    const wasTime = v?.currentTime || 0;
    const wasPlaying = !v?.paused;
    setSelectedQuality(idx);
    if (streams[idx]) {
      localStorage.setItem('df_preferred_quality', streams[idx].quality);
    }
    setQualityMenuOpen(false);
    setTimeout(() => {
      const nv = videoRef.current;
      if (nv) {
        nv.currentTime = wasTime;
        if (wasPlaying) nv.play().catch(() => {});
      }
    }, 80);
  };

  // Keyboard shortcuts (when not typing in an input)
  useEffect(() => {
    const onKey = (e) => {
      const tag = (e.target?.tagName || '').toLowerCase();
      if (tag === 'input' || tag === 'textarea' || e.target?.isContentEditable) return;
      // Only consume shortcuts if the player is in the viewport
      const wrap = wrapRef.current;
      if (!wrap) return;
      const r = wrap.getBoundingClientRect();
      if (r.bottom < 0 || r.top > window.innerHeight) return;
      switch (e.key.toLowerCase()) {
        case ' ': case 'spacebar': e.preventDefault(); togglePlay(); showKeyHint(videoRef.current?.paused ? 'Pausa' : 'Play'); break;
        case 'arrowleft': e.preventDefault(); skip(-10); break;
        case 'arrowright': e.preventDefault(); skip(10); break;
        case 'arrowup': e.preventDefault(); setVol(0.05); break;
        case 'arrowdown': e.preventDefault(); setVol(-0.05); break;
        case 'm': e.preventDefault(); toggleMute(); break;
        case 'f': e.preventDefault(); toggleFullscreen(); break;
        default: break;
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [togglePlay, skip, setVol, toggleMute, toggleFullscreen]);

  /* ── Scrub bar interactions ── */
  const onScrubMove = (e) => {
    const bar = scrubRef.current;
    if (!bar) return;
    const r = bar.getBoundingClientRect();
    const pct = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width));
    const t = pct * (duration || 0);
    setScrubHover({ x: pct * 100, t });
  };
  const onScrubLeave = () => setScrubHover(null);
  const onScrubClick = (e) => {
    const bar = scrubRef.current;
    if (!bar || !duration) return;
    const r = bar.getBoundingClientRect();
    const pct = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width));
    seekTo(pct * duration);
  };

  const progress = duration > 0 ? (currentTime / duration) * 100 : 0;
  const bufferedPct = duration > 0 ? (buffered / duration) * 100 : 0;

  return (
    <div
      ref={wrapRef}
      className="df-player-shell"
      onMouseMove={wakeControls}
      onTouchStart={wakeControls}
    >
      <video
        ref={videoRef}
        src={currentSrc}
        poster={preview ? api.proxyUrl(preview) : ''}
        preload="metadata"
        playsInline
        onClick={togglePlay}
      />

      {/* Big play (when paused) */}
      {!playing && (
        <div className="df-player-overlay-play visible" onClick={togglePlay}>
          <div className="df-player-big-play"><Icon.Play size={28}/></div>
        </div>
      )}

      {/* Buffering spinner */}
      {buffering && playing && <div className="df-player-spinner"/>}

      {/* Keyboard hint */}
      {keyHint && <div className="df-kb-hint">{keyHint}</div>}

      {/* Controls bar */}
      <div
        className={`df-player-bar ${showControls || !playing ? 'visible' : ''}`}
        onClick={(e) => e.stopPropagation()}
      >
        <div
          className="df-scrub-wrap"
          ref={scrubRef}
          onMouseMove={onScrubMove}
          onMouseLeave={onScrubLeave}
          onClick={onScrubClick}
        >
          <div className="df-scrub">
            <div className="df-scrub-buffer" style={{ width: `${bufferedPct}%` }}/>
            <div className="df-scrub-fill" style={{ width: `${progress}%` }}/>
            <div className="df-scrub-handle" style={{ left: `${progress}%` }}/>
          </div>
          {scrubHover && (
            <div
              className={`df-scrub-thumb ${hasScrubThumbs ? 'visible' : 'visible'}`}
              style={{
                left: `${scrubHover.x}%`,
                background: hasScrubThumbs ? '#000' : 'rgba(0,0,0,0.85)',
                width: hasScrubThumbs ? 160 : 70,
                aspectRatio: hasScrubThumbs ? '16/9' : 'auto',
                height: hasScrubThumbs ? 'auto' : 28,
              }}
            >
              {hasScrubThumbs && (
                <img
                  src={getThumbUrl(scrubHover.t)}
                  alt=""
                  onError={(e) => { e.currentTarget.style.opacity = 0; }}
                />
              )}
              <div className="df-scrub-thumb-time">{formatTime(scrubHover.t)}</div>
            </div>
          )}
        </div>

        <div className="df-player-ctrl-row">
          <button className="df-player-btn" onClick={togglePlay} aria-label={playing ? 'Pausa' : 'Play'}>
            {playing ? <Icon.Pause size={16}/> : <Icon.Play size={16}/>}
          </button>
          <button className="df-player-btn" onClick={() => skip(-10)} aria-label="Indietro 10s">
            <Icon.Back10 size={20}/>
          </button>
          <button className="df-player-btn" onClick={() => skip(10)} aria-label="Avanti 10s">
            <Icon.Skip10 size={20}/>
          </button>
          <button className="df-player-btn" onClick={toggleMute} aria-label={muted ? 'Riattiva audio' : 'Disattiva audio'}>
            {muted || volume === 0 ? <Icon.VolumeOff size={16}/> : <Icon.Volume size={16}/>}
          </button>
          <span className="df-player-time">
            {formatTime(currentTime)} / {formatTime(duration)}
          </span>
          <span className="df-player-spacer"/>
          {streams.length > 1 && (
            <div style={{ position: 'relative' }}>
              <button
                className="df-quality-btn"
                onClick={() => setQualityMenuOpen(o => !o)}
              >{currentStream?.quality || 'Auto'}</button>
              {qualityMenuOpen && (
                <div className="df-quality-menu" onMouseLeave={() => setQualityMenuOpen(false)}>
                  {streams.map((s, i) => (
                    <button
                      key={i}
                      className={`df-quality-menu-item ${i === selectedQuality ? 'active' : ''}`}
                      onClick={() => changeQuality(i)}
                    >{s.quality}</button>
                  ))}
                </div>
              )}
            </div>
          )}
          <button className="df-player-btn" onClick={onDownload} aria-label="Download">
            <Icon.Download size={16}/>
          </button>
          <button className="df-player-btn" onClick={toggleFullscreen} aria-label="Schermo intero">
            <Icon.Maximize size={16}/>
          </button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  Icon, formatTime, setCookie, getCookie, useMediaQuery,
  AgeGate, useWatchLater, useToast, ToastView,
  Header, VideoCard, VideoGrid, ModelCard, ModelGrid, CategoryCard,
  Pagination, CustomPlayer,
});
