/* ════════════════════════════════════════════════
   Dashboard — komponen UI bersama
   ════════════════════════════════════════════════ */

/* Toast notifikasi global */
function useToast() {
  const [toast, setToast] = useState(null);
  const show = (msg) => { setToast(msg); setTimeout(() => setToast(null), 2200); };
  const node = toast ? (
    <div style={{ position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)', zIndex: 500, background: 'var(--brand-deep)', color: '#fff', padding: '12px 22px', borderRadius: 12, fontSize: 14, fontWeight: 700, boxShadow: '0 12px 36px rgba(0,0,0,.3)' }}>{toast}</div>
  ) : null;
  return [node, show];
}

/* Kartu panel */
function DCard({ children, pad = '22px', style }) {
  return <div style={{ background: 'var(--surface)', borderRadius: 16, border: '1px solid var(--border-soft)', boxShadow: 'var(--shadow-warm-sm, 0 4px 14px rgba(120,80,30,.06))', padding: pad, ...style }}>{children}</div>;
}

/* Tombol dashboard */
function DBtn({ children, onClick, variant = 'default', size = 'md', disabled, type = 'button', style }) {
  const pads = { sm: '7px 12px', md: '10px 18px', lg: '13px 24px' };
  const fs = { sm: 12.5, md: 14, lg: 15 };
  const variants = {
    default: { background: 'var(--surface)', color: 'var(--ink-deep)', border: '1.5px solid var(--border)' },
    primary: { background: 'var(--navy)', color: '#fff', border: '1.5px solid var(--navy)' },
    orange:  { background: 'var(--orange)', color: '#fff', border: '1.5px solid var(--orange)' },
    success: { background: 'var(--sage)', color: '#fff', border: '1.5px solid var(--sage)' },
    danger:  { background: '#fff', color: '#DC2626', border: '1.5px solid #FECACA' },
    ghost:   { background: 'transparent', color: 'var(--muted)', border: '1.5px solid transparent' },
  };
  return (
    <button type={type} onClick={onClick} disabled={disabled} style={{
      padding: pads[size], fontSize: fs[size], fontWeight: 700, borderRadius: 10, cursor: disabled ? 'not-allowed' : 'pointer',
      fontFamily: 'inherit', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7, whiteSpace: 'nowrap',
      opacity: disabled ? .5 : 1, transition: 'all .15s', ...variants[variant], ...style,
    }}>{children}</button>
  );
}

/* Modal */
function Modal({ open, onClose, title, sub, children, width = '520px' }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, background: 'rgba(10,20,45,.6)', zIndex: 400, display: 'flex', alignItems: 'flex-start', justifyContent: 'center', padding: '40px 16px', backdropFilter: 'blur(3px)', overflowY: 'auto' }}>
      <div onClick={e => e.stopPropagation()} style={{ background: 'var(--surface)', borderRadius: 18, width: '100%', maxWidth: width, boxShadow: '0 30px 80px rgba(0,0,0,.35)', marginTop: 'auto', marginBottom: 'auto' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', padding: '22px 26px 0' }}>
          <div>
            <div style={{ fontFamily: 'var(--font-d)', fontSize: 20, fontWeight: 900, color: 'var(--ink-deep)' }}>{title}</div>
            {sub && <div style={{ fontSize: 13, color: 'var(--muted)', marginTop: 2 }}>{sub}</div>}
          </div>
          <button onClick={onClose} style={{ background: 'var(--bg2)', border: 'none', borderRadius: 8, width: 32, height: 32, cursor: 'pointer', color: 'var(--ink-deep)', fontSize: 16, flexShrink: 0 }}>✕</button>
        </div>
        <div style={{ padding: '18px 26px 26px' }}>{children}</div>
      </div>
    </div>
  );
}

/* Field input dashboard */
function DField({ label, children, hint }) {
  return (
    <div style={{ marginBottom: 15 }}>
      {label && <label style={{ display: 'block', fontSize: 12.5, fontWeight: 700, color: 'var(--ink-deep)', marginBottom: 6 }}>{label}</label>}
      {children}
      {hint && <div style={{ fontSize: 11.5, color: 'var(--muted)', marginTop: 4 }}>{hint}</div>}
    </div>
  );
}
const dInp = { width: '100%', padding: '11px 14px', borderRadius: 10, border: '1.5px solid var(--border)', fontSize: 14, fontFamily: 'inherit', background: 'var(--surface)', color: 'var(--ink-deep)', boxSizing: 'border-box' };

/* Tabel sederhana */
function DTable({ cols, children }) {
  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 520 }}>
        <thead>
          <tr style={{ borderBottom: '1.5px solid var(--border-soft)' }}>
            {cols.map((c, i) => <th key={i} style={{ textAlign: 'left', padding: '10px 12px', fontSize: 11.5, fontWeight: 800, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '.04em', whiteSpace: 'nowrap' }}>{c}</th>)}
          </tr>
        </thead>
        <tbody>{children}</tbody>
      </table>
    </div>
  );
}
function DTd({ children, style }) {
  return <td style={{ padding: '12px', fontSize: 13.5, color: 'var(--ink)', borderBottom: '1px solid var(--border-soft)', ...style }}>{children}</td>;
}

/* Badge status */
function Pill({ children, color = 'gray' }) {
  const c = {
    green:  ['rgba(31,107,71,.12)', '#1F6B47'],
    orange: ['rgba(232,145,42,.14)', '#C26F12'],
    blue:   ['rgba(27,47,110,.12)', '#1B2F6E'],
    red:    ['rgba(220,38,38,.1)', '#DC2626'],
    gray:   ['var(--bg2)', 'var(--muted)'],
  }[color];
  return <span style={{ display: 'inline-block', padding: '3px 10px', borderRadius: 999, background: c[0], color: c[1], fontSize: 11.5, fontWeight: 800 }}>{children}</span>;
}

/* Kartu statistik overview */
function StatCard({ icon, num, label, accent }) {
  return (
    <DCard pad="20px">
      <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
        <div style={{ width: 46, height: 46, borderRadius: 12, background: accent || 'var(--navy)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 22, flexShrink: 0 }}>{icon}</div>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontFamily: 'var(--font-d)', fontSize: 22, fontWeight: 900, color: 'var(--ink-deep)', lineHeight: 1.05, wordBreak: 'break-word', overflowWrap: 'anywhere' }}>{num}</div>
          <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 4 }}>{label}</div>
        </div>
      </div>
    </DCard>
  );
}

/* Modal crop gambar — pan + zoom sesuai rasio target */
function CropModal({ src, ratio, onCancel, onDone }) {
  const frameRef = React.useRef();
  const imgRef = React.useRef();
  const [img, setImg] = useState(null);
  const [zoom, setZoom] = useState(1);
  const [pos, setPos] = useState({ x: 0, y: 0 });
  const drag = React.useRef(null);
  const [rw, rh] = (ratio || '16/9').split('/').map(Number);

  const frameW = () => frameRef.current ? frameRef.current.clientWidth : 320;
  const frameH = () => frameW() * rh / rw;

  useEffect(() => {
    const im = new Image();
    im.onload = () => { setImg(im); setZoom(1); center(im, 1); };
    im.src = src;
  }, [src]);

  const coverScale = (im) => Math.max(frameW() / im.width, frameH() / im.height);
  const dispSize = (im, z) => { const s = coverScale(im) * z; return { w: im.width * s, h: im.height * s, s }; };
  const center = (im, z) => { const d = dispSize(im, z); setPos({ x: (frameW() - d.w) / 2, y: (frameH() - d.h) / 2 }); };
  const clamp = (p, im, z) => { const d = dispSize(im, z); return { x: Math.min(0, Math.max(frameW() - d.w, p.x)), y: Math.min(0, Math.max(frameH() - d.h, p.y)) }; };

  const onZoom = (z) => { setZoom(z); if (img) setPos(p => clamp({ x: p.x - (dispSize(img, z).w - dispSize(img, zoom).w) / 2, y: p.y - (dispSize(img, z).h - dispSize(img, zoom).h) / 2 }, img, z)); };
  const start = (e) => { const pt = e.touches ? e.touches[0] : e; drag.current = { px: pt.clientX, py: pt.clientY, ox: pos.x, oy: pos.y }; };
  const move = (e) => { if (!drag.current || !img) return; const pt = e.touches ? e.touches[0] : e; setPos(clamp({ x: drag.current.ox + (pt.clientX - drag.current.px), y: drag.current.oy + (pt.clientY - drag.current.py) }, img, zoom)); };
  const end = () => { drag.current = null; };

  const save = () => {
    if (!img) return;
    const d = dispSize(img, zoom);
    const OW = Math.min(1400, Math.round(frameW() * 2)), OH = Math.round(OW * rh / rw);
    const cv = document.createElement('canvas'); cv.width = OW; cv.height = OH;
    const ctx = cv.getContext('2d');
    const srcX = (-pos.x) / d.s, srcY = (-pos.y) / d.s, srcW = frameW() / d.s, srcH = frameH() / d.s;
    ctx.drawImage(img, srcX, srcY, srcW, srcH, 0, 0, OW, OH);
    cv.toBlob(b => onDone(b, cv.toDataURL('image/jpeg', 0.9)), 'image/jpeg', 0.9);
  };

  return (
    <Modal open onClose={onCancel} title="Atur Gambar" width="440px">
      <p style={{ fontSize: 12.5, color: 'var(--muted)', margin: '0 0 12px' }}>Geser untuk memposisikan, gunakan slider untuk memperbesar. Area dalam bingkai yang akan disimpan.</p>
      <div ref={frameRef} onMouseDown={start} onMouseMove={move} onMouseUp={end} onMouseLeave={end} onTouchStart={start} onTouchMove={move} onTouchEnd={end}
        style={{ position: 'relative', width: '100%', aspectRatio: ratio, borderRadius: 12, overflow: 'hidden', background: '#000', cursor: 'grab', touchAction: 'none', userSelect: 'none' }}>
        {img && <img ref={imgRef} src={src} alt="" draggable={false} style={{ position: 'absolute', left: pos.x, top: pos.y, width: dispSize(img, zoom).w, height: dispSize(img, zoom).h, maxWidth: 'none' }} />}
        <div style={{ position: 'absolute', inset: 0, boxShadow: 'inset 0 0 0 2px rgba(255,255,255,.5)', pointerEvents: 'none' }} />
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '14px 0' }}>
        <span style={{ fontSize: 16 }}>🔍</span>
        <input type="range" min="1" max="3" step="0.01" value={zoom} onChange={e => onZoom(parseFloat(e.target.value))} style={{ flex: 1, accentColor: 'var(--sage)' }} />
      </div>
      <div style={{ display: 'flex', gap: 10 }}>
        <DBtn variant="orange" size="lg" onClick={save} style={{ flex: 1 }}>✓ Simpan Gambar</DBtn>
        <DBtn size="lg" onClick={onCancel}>Batal</DBtn>
      </div>
    </Modal>
  );
}

/* Upload gambar (mock-aware) + crop */
function ImageUpload({ value, onChange, label = 'Gambar', ratio = '16/9' }) {
  const ref = React.useRef();
  const [busy, setBusy] = useState(false);
  const [cropSrc, setCropSrc] = useState(null);

  const pick = (e) => { const file = e.target.files[0]; if (!file) return; setCropSrc(URL.createObjectURL(file)); e.target.value = ''; };

  const uploadBlob = async (blob, dataUrl) => {
    onChange(dataUrl); setBusy(true); setCropSrc(null);
    try {
      const fd = new FormData(); fd.append('file', blob, 'crop.jpg'); fd.append('_preview', dataUrl);
      const res = await api.post('upload.php', fd);
      if (res.ok) onChange(res.data?.url || res.url || dataUrl);
    } catch {} finally { setBusy(false); }
  };

  return (
    <DField label={label}>
      <div onClick={() => ref.current?.click()} style={{ aspectRatio: ratio, borderRadius: 12, border: '2px dashed var(--border)', background: 'var(--bg2)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', overflow: 'hidden', position: 'relative' }}>
        {value ? <img src={value} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : <span style={{ color: 'var(--muted)', fontSize: 13, fontWeight: 600 }}>{busy ? 'Mengunggah…' : '📷 Klik untuk unggah'}</span>}
        {value && !busy && <span style={{ position: 'absolute', bottom: 8, right: 8, background: 'rgba(0,0,0,.6)', color: '#fff', fontSize: 11, fontWeight: 700, padding: '4px 9px', borderRadius: 7 }}>Ganti / Crop</span>}
      </div>
      <input ref={ref} type="file" accept="image/*" onChange={pick} style={{ display: 'none' }} />
      {cropSrc && <CropModal src={cropSrc} ratio={ratio} onCancel={() => setCropSrc(null)} onDone={uploadBlob} />}
    </DField>
  );
}

Object.assign(window, { useToast, DCard, DBtn, Modal, DField, dInp, DTable, DTd, Pill, StatCard, ImageUpload, CropModal });
