/* global React, Icon */
const { useState, useRef, useEffect, useMemo } = React;

/* ---------- Mock data ---------- */
const NAMESPACES = [
  { id: 'you',       label: 'julien-c',      kind: 'user', avatar: 'https://cdn-avatars.huggingface.co/v1/production/uploads/5dd96eb166059660ed1ee413/NQtzmrDdbG0H8qkZvRyGk.jpeg' },
  { id: 'acme-ai',   label: 'acme-ai',       kind: 'org',  avatar: 'https://cdn-avatars.huggingface.co/v1/production/uploads/620760a26e3b7210c2ff1943/-s1gyJfvbE1RgO5iBeNOi.png' },
  { id: 'lab-x',     label: 'lab-x',         kind: 'org',  avatar: 'https://cdn-avatars.huggingface.co/v1/production/uploads/noauth/1CJGiHk.png' },
];

const INITIAL_BUCKETS = [
  { id: 'b1', name: 'production-llms',   namespace: 'acme-ai', privacy: 'private', items: 18,  usedGB: 420,  capGB: 1024, color: '#2563eb' },
  { id: 'b2', name: 'eval-harness',      namespace: 'acme-ai', privacy: 'private', items: 7,   usedGB: 82,   capGB: 512,  color: '#16a34a' },
  { id: 'b3', name: 'research-sandbox',  namespace: 'lab-x',   privacy: 'team',    items: 42,  usedGB: 930,  capGB: 1024, color: '#f59e0b' },
  { id: 'b4', name: 'my-weekend-models', namespace: 'you',     privacy: 'private', items: 3,   usedGB: 12,   capGB: 256,  color: '#a855f7' },
  { id: 'b5', name: 'open-mirror',       namespace: 'acme-ai', privacy: 'public',  items: 124, usedGB: 1820, capGB: 2048, color: '#0ea5e9' },
  { id: 'b6', name: 'scratch',           namespace: 'you',     privacy: 'private', items: 1,   usedGB: 4,    capGB: 128,  color: '#14b8a6' },
];

/* source repo folder tree (for the Source subfolder picker) */
const SOURCE_FOLDERS = [
  { path: '/', label: '(entire repo)',  files: 47, sizeGB: 54.2 },
  { path: '/tokenizer',     label: 'tokenizer',    files: 6,  sizeGB: 0.01 },
  { path: '/weights',       label: 'weights',      files: 14, sizeGB: 52.8 },
  { path: '/weights/fp16',  label: 'weights/fp16', files: 7,  sizeGB: 26.4 },
  { path: '/weights/fp8',   label: 'weights/fp8',  files: 7,  sizeGB: 13.2 },
  { path: '/config',        label: 'config',       files: 4,  sizeGB: 0.001 },
  { path: '/examples',      label: 'examples',     files: 9,  sizeGB: 0.08 },
];

const DEFAULTS = /*EDITMODE-BEGIN*/{
  "placement": "between",
  "style": "black",
  "label": "Copy to Bucket",
  "showArrow": true,
  "showNewBadge": false,
  "multiBucket": true
}/*EDITMODE-END*/;

window.INITIAL_BUCKETS = INITIAL_BUCKETS;
window.NAMESPACES = NAMESPACES;
window.SOURCE_FOLDERS = SOURCE_FOLDERS;
window.DEFAULTS = DEFAULTS;

/* ---------- Site header ---------- */
function SiteHeader() {
  return (
    <header className="site-header">
      <div className="container site-header-row">
        <a className="logo" href="#">
          <Icon.HfLogo />
          <span className="logo-text">Hugging Face</span>
        </a>
        <div className="search">
          <Icon.Search className="s-icon" />
          <input placeholder="Search models, datasets, users..." />
        </div>
        <ul className="main-nav">
          <li><a className="nav-link" href="#">Models</a></li>
          <li><a className="nav-link" href="#">Datasets</a></li>
          <li><a className="nav-link" href="#">Spaces</a></li>
          <li><a className="nav-link is-active" href="#">Buckets <span className="new-pill">NEW</span></a></li>
          <li><a className="nav-link" href="#">Docs</a></li>
          <li><a className="nav-link" href="#">Enterprise</a></li>
          <li><a className="nav-link" href="#">Pricing</a></li>
          <li><hr className="nav-sep" /></li>
          <li><a className="nav-link" href="#"><img className="nav-avatar" src="https://cdn-avatars.huggingface.co/v1/production/uploads/5dd96eb166059660ed1ee413/NQtzmrDdbG0H8qkZvRyGk.jpeg" alt="" /></a></li>
        </ul>
      </div>
    </header>
  );
}

/* ---------- Bucket row ---------- */
function BucketRow({ bucket, isSelected, isIn, onPick }) {
  const pct = Math.round((bucket.usedGB / bucket.capGB) * 100);
  const meterCls = pct >= 95 ? 'crit' : pct >= 80 ? 'warn' : '';
  const PrivacyIcon = bucket.privacy === 'public' ? Icon.Globe : bucket.privacy === 'team' ? Icon.Users : Icon.Lock;
  return (
    <button
      className={`bucket-row ${isSelected ? 'is-selected' : ''} ${isIn ? 'is-in' : ''}`}
      onClick={() => !isIn && onPick(bucket)}
      disabled={isIn}
    >
      <div className="bucket-ico" style={{ background: bucket.color + '22', color: bucket.color }}>
        <Icon.BucketFilled />
      </div>
      <div className="bucket-main">
        <div className="bucket-name">
          {bucket.name}
          {isIn && <span className="bucket-badge">In bucket</span>}
        </div>
        <div className="bucket-meta">
          <PrivacyIcon style={{ fontSize: 11 }} /> {bucket.privacy}
          <span className="dot" />
          {bucket.items} items
          <span className="dot" />
          {bucket.usedGB} / {bucket.capGB} GB
        </div>
        <div className={`bucket-meter ${meterCls}`}><div style={{ width: pct + '%' }} /></div>
      </div>
      {isSelected && <Icon.Check className="bucket-check" />}
    </button>
  );
}

/* ---------- Bucket picker modal: Source → Destination → Summary ---------- */
function BucketPicker({ buckets, onConfirm, onClose }) {
  // Source
  const [sourceSubfolder, setSourceSubfolder] = useState('/');
  const sourceFolder = SOURCE_FOLDERS.find(f => f.path === sourceSubfolder) || SOURCE_FOLDERS[0];

  // Destination — mode: existing | new
  const [destMode, setDestMode] = useState('existing');

  // existing bucket
  const [destBucketId, setDestBucketId] = useState(buckets[0]?.id || '');
  const destBucket = buckets.find(b => b.id === destBucketId);

  // new bucket
  const [newNs, setNewNs] = useState('you');
  const [newName, setNewName] = useState('qwen3-mirror');
  const [newVis, setNewVis] = useState('private');

  // destination subfolder
  const defaultDestSub = sourceSubfolder === '/' ? '/Qwen/Qwen3.6-27B' : `/Qwen/Qwen3.6-27B${sourceSubfolder}`;
  const [destSubfolder, setDestSubfolder] = useState(defaultDestSub);
  const [destTouched, setDestTouched] = useState(false);
  useEffect(() => {
    if (!destTouched) setDestSubfolder(defaultDestSub);
  }, [defaultDestSub, destTouched]);

  useEffect(() => {
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onEsc);
    return () => document.removeEventListener('keydown', onEsc);
  }, [onClose]);

  // Summary numbers
  const files = sourceFolder.files;
  const sizeGB = sourceFolder.sizeGB;
  // Cap at 58s so it's always < 1 min
  const etaSec = Math.max(4, Math.min(58, Math.round(6 + sizeGB * 0.9)));

  const destReady =
    destMode === 'existing' ? !!destBucketId : !!newName.trim();

  const confirm = () => {
    if (!destReady) return;
    let target;
    if (destMode === 'existing') {
      target = { ...destBucket, destSubfolder, sourceSubfolder, files, sizeGB };
    } else {
      target = {
        id: 'b' + Date.now(),
        name: newName.trim(),
        namespace: newNs,
        privacy: newVis,
        items: 0, usedGB: 0, capGB: 256, color: '#14b8a6',
        destSubfolder, sourceSubfolder, files, sizeGB, _new: true,
      };
    }
    onConfirm([target]);
  };

  const destLabel = destMode === 'existing'
    ? (destBucket ? `${destBucket.namespace}/${destBucket.name}` : '—')
    : `${newNs}/${newName || '…'}`;

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" role="dialog" aria-modal="true" style={{ maxWidth: 680 }}>
        <div className="modal-head">
          <div className="modal-title">
            <Icon.BucketFilled style={{ color: 'var(--color-gray-700)' }} />
            Copy to Bucket
          </div>
          <button className="modal-close" onClick={onClose} aria-label="Close"><Icon.X /></button>
        </div>

        <div className="modal-body">
          {/* ── SOURCE ── */}
          <div className="section-head">
            <span className="section-num">1</span>
            <span className="section-title">Source</span>
          </div>

          <div className="field">
            <label className="field-label">Model</label>
            <div className="locked-field">
              <img className="ns-avatar" src="https://cdn-avatars.huggingface.co/v1/production/uploads/620760a26e3b7210c2ff1943/-s1gyJfvbE1RgO5iBeNOi.png" alt="" />
              <span className="mono">Qwen/Qwen3.6-27B</span>
              <span className="locked-hint"><Icon.Lock style={{ fontSize: 12 }} /> from this page</span>
            </div>
          </div>

          <div className="field">
            <label className="field-label">
              Subfolder <span className="muted">· optional</span>
            </label>
            <select
              className="text-input select"
              value={sourceSubfolder}
              onChange={(e) => setSourceSubfolder(e.target.value)}
            >
              {SOURCE_FOLDERS.map(f => (
                <option key={f.path} value={f.path}>
                  {f.label}  ·  {f.files} files · {f.sizeGB < 0.01 ? (f.sizeGB * 1024).toFixed(1) + ' MB' : f.sizeGB + ' GB'}
                </option>
              ))}
            </select>
          </div>

          {/* ── DESTINATION ── */}
          <div className="section-head" style={{ marginTop: 22 }}>
            <span className="section-num">2</span>
            <span className="section-title">Destination</span>
          </div>

          <div className="pill-tabs">
            <button
              className={`pill-tab ${destMode === 'existing' ? 'is-active' : ''}`}
              onClick={() => setDestMode('existing')}
            >Existing Bucket</button>
            <button
              className={`pill-tab ${destMode === 'new' ? 'is-active' : ''}`}
              onClick={() => setDestMode('new')}
            >New Bucket</button>
          </div>

          {destMode === 'existing' && (
            <div className="field">
              <label className="field-label">Bucket</label>
              <div className="bucket-select-list">
                {buckets.map(b => {
                  const ns = NAMESPACES.find(n => n.id === b.namespace);
                  const pct = Math.round((b.usedGB / b.capGB) * 100);
                  const selected = destBucketId === b.id;
                  return (
                    <button
                      key={b.id}
                      type="button"
                      className={`bucket-select-row ${selected ? 'is-selected' : ''}`}
                      onClick={() => setDestBucketId(b.id)}
                    >
                      <div className={`radio-dot-lg ${selected ? 'on' : ''}`} />
                      <img className="ns-avatar sm" src={ns?.avatar} alt="" />
                      <div className="bucket-main">
                        <div className="bucket-name">
                          <span className="muted mono">{ns?.label}/</span>
                          <span className="mono">{b.name}</span>
                          <span className={`ns-chip ${ns?.kind}`}>{ns?.kind}</span>
                        </div>
                        <div className="bucket-meta">
                          {b.privacy} · {b.items} items · {b.usedGB}/{b.capGB} GB · {pct}%
                        </div>
                      </div>
                      <div className="size-chip">{b.usedGB} GB</div>
                    </button>
                  );
                })}
              </div>
            </div>
          )}

          {destMode === 'new' && (
            <>
              <div className="field">
                <label className="field-label">Namespace</label>
                <div className="ns-select">
                  {NAMESPACES.map(n => (
                    <button
                      key={n.id}
                      type="button"
                      className={`ns-opt ${newNs === n.id ? 'on' : ''}`}
                      onClick={() => setNewNs(n.id)}
                    >
                      <img className="ns-avatar sm" src={n.avatar} alt="" />
                      <span className="mono">{n.label}</span>
                      <span className={`ns-chip ${n.kind}`}>{n.kind}</span>
                    </button>
                  ))}
                </div>
              </div>

              <div className="field">
                <label className="field-label">Bucket name</label>
                <div className="prefix-field">
                  <span className="prefix mono">{NAMESPACES.find(n => n.id === newNs)?.label} /</span>
                  <input
                    className="text-input"
                    value={newName}
                    onChange={e => setNewName(e.target.value)}
                    placeholder="my-bucket"
                  />
                </div>
              </div>

              <div className="field">
                <label className="field-label">Visibility</label>
                <div className="vis-toggle">
                  <button
                    className={`vis-opt ${newVis === 'public' ? 'on' : ''}`}
                    onClick={() => setNewVis('public')}
                  >
                    <Icon.Globe /> Public
                  </button>
                  <button
                    className={`vis-opt ${newVis === 'private' ? 'on' : ''}`}
                    onClick={() => setNewVis('private')}
                  >
                    <Icon.Lock /> Private
                  </button>
                </div>
              </div>
            </>
          )}

          <div className="field" style={{ marginTop: 4 }}>
            <label className="field-label">
              Destination subfolder <span className="muted">· optional, recommended</span>
            </label>
            <input
              className="text-input mono"
              value={destSubfolder}
              onChange={(e) => { setDestSubfolder(e.target.value); setDestTouched(true); }}
              placeholder="/models/qwen3"
            />
            <div className="helper">
              Defaults to mirror the source path. {destTouched && (
                <button className="link" onClick={() => { setDestTouched(false); setDestSubfolder(defaultDestSub); }}>Reset</button>
              )}
            </div>
          </div>

          {/* ── SUMMARY ── */}
          <div className="section-head" style={{ marginTop: 22 }}>
            <span className="section-num">3</span>
            <span className="section-title">Summary</span>
          </div>

          <div className="summary-card">
            <div className="summary-row">
              <span className="summary-k">Source</span>
              <span className="summary-v mono">Qwen/Qwen3.6-27B{sourceSubfolder === '/' ? '' : sourceSubfolder}</span>
            </div>
            <div className="summary-arrow">↓</div>
            <div className="summary-row">
              <span className="summary-k">Destination</span>
              <span className="summary-v mono">{destLabel}{destSubfolder}</span>
            </div>
            <div className="summary-stats">
              <div className="stat">
                <div className="stat-v">{files}</div>
                <div className="stat-k">files</div>
              </div>
              <div className="stat">
                <div className="stat-v">{sizeGB < 0.01 ? (sizeGB * 1024).toFixed(1) + ' MB' : sizeGB + ' GB'}</div>
                <div className="stat-k">total size</div>
              </div>
              <div className="stat">
                <div className="stat-v">~{etaSec}s</div>
                <div className="stat-k">estimated time</div>
              </div>
            </div>
          </div>
        </div>

        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary-modal" disabled={!destReady} onClick={confirm}>
            Copy to Bucket
          </button>
        </div>
      </div>
    </div>
  );
}

/* ---------- Already-in popover ---------- */
function AlreadyInPopover({ buckets, inIds, onAdd, onRemove, onClose }) {
  const ref = useRef(null);
  useEffect(() => {
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [onClose]);
  const inBuckets = buckets.filter(b => inIds.includes(b.id));
  return (
    <div className="popover" style={{ width: 320 }} ref={ref}>
      <div className="popover-head">
        <div className="popover-title"><Icon.Check style={{ color: 'var(--color-green-600)' }} /> In {inBuckets.length} bucket{inBuckets.length === 1 ? '' : 's'}</div>
        <div className="popover-sub">Qwen3.6-27B is currently pinned to these buckets.</div>
      </div>
      <div className="mini-list">
        {inBuckets.map(b => (
          <div className="mini-row" key={b.id}>
            <div className="bucket-ico" style={{ width: 24, height: 24, background: b.color + '22', color: b.color, borderRadius: 6 }}>
              <Icon.BucketFilled />
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontWeight: 600 }}>{b.name}</div>
              <div style={{ fontSize: 11, color: 'var(--color-gray-500)' }}>copied · v1 · 2d ago</div>
            </div>
            <button className="remove" title="Remove from bucket" onClick={() => onRemove(b.id)}><Icon.X /></button>
          </div>
        ))}
      </div>
      <div className="create-row" onClick={onAdd}>
        <div className="create-ico"><Icon.Plus /></div>
        <div>
          <div style={{ fontWeight: 600 }}>Copy to another bucket…</div>
        </div>
      </div>
    </div>
  );
}

/* ---------- Copy-to-Bucket button ---------- */
function CopyToBucketButton({ tweaks, buckets, setBuckets, inIds, setInIds, pushToast }) {
  const [open, setOpen] = useState(false);
  const [manageOpen, setManageOpen] = useState(false);
  const [phase, setPhase] = useState('idle'); // idle | busy | done
  const [progress, setProgress] = useState(0);
  const [lastCopied, setLastCopied] = useState(null);
  const doneTimer = useRef(null);

  const runCopy = (chosen) => {
    setOpen(false);
    setPhase('busy');
    setProgress(0);
    let p = 0;
    const tick = setInterval(() => {
      p += 6 + Math.random() * 9;
      if (p >= 100) {
        p = 100;
        clearInterval(tick);
        setProgress(100);
        setInIds(prev => Array.from(new Set([...prev, ...chosen.map(c => c.id)])));
        setLastCopied(chosen);
        setPhase('done');
        pushToast({
          id: Date.now(),
          msg: chosen.length === 1
            ? <>Copied to <b>{chosen[0].name}</b></>
            : <>Copied to <b>{chosen.length} buckets</b></>,
          action: 'View in bucket',
        });
        // return to idle label but keep "in N buckets" state
        clearTimeout(doneTimer.current);
        doneTimer.current = setTimeout(() => setPhase('idle'), 2400);
      } else {
        setProgress(p);
      }
    }, 120);
  };

  const handleRemove = (id) => {
    setInIds(prev => prev.filter(x => x !== id));
    const b = buckets.find(x => x.id === id);
    pushToast({ id: Date.now(), msg: <>Removed from <b>{b?.name}</b></>, action: 'Undo' });
  };

  /* ---- styling variants from tweaks ---- */
  const styleCls =
    tweaks.style === 'blue' ? 'btn-outlined-blue' :
    tweaks.style === 'black' ? 'btn-black-sibling' : '';

  const isBlack = tweaks.style === 'black';

  // If already in at least one bucket → show "In N buckets" chip button
  if (phase === 'idle' && inIds.length > 0) {
    return (
      <div className="popover-wrap">
        <button
          className={`btn btn-copy ${styleCls}`}
          onClick={() => setManageOpen(v => !v)}
        >
          {isBlack ? <span className="arrow-glyph">→</span> : <Icon.BucketFilled style={{ color: isBlack ? '#86efac' : 'var(--color-green-600)' }} />}
          In {inIds.length} bucket{inIds.length === 1 ? '' : 's'}
          <Icon.ChevDown className="chev" />
        </button>
        {manageOpen && (
          <AlreadyInPopover
            buckets={buckets}
            inIds={inIds}
            onClose={() => setManageOpen(false)}
            onAdd={() => { setManageOpen(false); setOpen(true); }}
            onRemove={handleRemove}
          />
        )}
        {open && (
          <BucketPicker
            buckets={buckets}
            alreadyIn={inIds}
            multi={tweaks.multiBucket}
            onConfirm={(chosen) => {
              // register brand-new buckets in the list
              const fresh = chosen.filter(c => c._new);
              if (fresh.length) setBuckets(prev => [...fresh, ...prev]);
              runCopy(chosen);
            }}
            onClose={() => setOpen(false)}
          />
        )}
      </div>
    );
  }

  return (
    <div className="popover-wrap">
      <button
        className={`btn btn-copy ${styleCls} ${phase === 'busy' ? 'busy' : ''} ${phase === 'done' ? 'done' : ''}`}
        onClick={() => phase === 'idle' && setOpen(v => !v)}
        disabled={phase === 'busy'}
      >
        {phase === 'busy' && (
          <>
            <svg width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ animation: 'spin 900ms linear infinite' }}>
              <circle cx="12" cy="12" r="9" opacity=".2" />
              <path d="M21 12a9 9 0 0 0-9-9" strokeLinecap="round" />
            </svg>
            Copying… {Math.round(progress)}%
            <span className="btn-progress" style={{ width: progress + '%' }} />
          </>
        )}
        {phase === 'done' && (<><Icon.Check /> Copied</>)}
        {phase === 'idle' && (
          <>
            {tweaks.showArrow
              ? <span className="arrow-glyph">→</span>
              : <Icon.Bucket />}
            {tweaks.label}
            {tweaks.showNewBadge && <span className="new-badge">NEW</span>}
            {!isBlack && <Icon.ChevDown className="chev" />}
          </>
        )}
      </button>
      {open && (
        <BucketPicker
          buckets={buckets}
          alreadyIn={inIds}
          multi={tweaks.multiBucket}
          onConfirm={(chosen) => {
            const fresh = chosen.filter(c => c._new);
            if (fresh.length) setBuckets(prev => [...fresh, ...prev]);
            runCopy(chosen);
          }}
          onClose={() => setOpen(false)}
        />
      )}
    </div>
  );
}

window.SiteHeader = SiteHeader;
window.CopyToBucketButton = CopyToBucketButton;
