// components.jsx — UI building blocks for Color Shades
const { useState: useStateC, useEffect: useEffectC, useRef: useRefC } = React;
const CUc = window.ColorUtil;

function TopBar({ baseHex, dark, onToggleDark, onExport, activeTab, onTabChange }) {
  const tabs = [
    { id: 'palette', label: 'Palette' },
    { id: 'shades',  label: 'Shades & Tints' },
    { id: 'ui',      label: 'UI Check' },
  ];
  return (
    <header className="topbar">
      <div className="brand">
        <div className="brand-dot" style={{ background: baseHex }} />
        <div>
          <div className="brand-name">Shades</div>
          <div className="brand-sub">Color shade generator</div>
        </div>
      </div>
      <nav className="topbar-tabs" aria-label="Sections">
        {tabs.map(tab => (
          <button
            key={tab.id}
            className={`topbar-tab ${activeTab === tab.id ? 'active' : ''}`}
            onClick={() => onTabChange(tab.id)}>
            {tab.label}
          </button>
        ))}
      </nav>
      <div className="top-actions">
        <button className="btn-ghost" onClick={onToggleDark} aria-label="Toggle theme">
          {dark ? <SunIcon /> : <MoonIcon />}
        </button>
        <button className="btn-primary" onClick={onExport}>
          <ExportIcon /> Export
        </button>
      </div>
    </header>);
}

function PaletteView({ colors, onGenerate, onToggleLock, onRemove, onAddAt, onEditHex }) {
  const CUp = window.ColorUtil;

  const closestName = hex => CUp.closestNamed(hex).name.replace(/([A-Z])/g, ' $1').trim();

  const [editingId, setEditingId] = React.useState(null);
  const [hexDraft, setHexDraft]   = React.useState('');
  const [copied, setCopied]       = React.useState(null);
  const copyTimer  = React.useRef();
  const generateFn = React.useRef(onGenerate);
  generateFn.current = onGenerate;

  React.useEffect(() => {
    const handler = e => {
      if (e.code === 'Space' && e.target === document.body) {
        e.preventDefault();
        generateFn.current();
      }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, []);

  const startEdit  = (id, hex) => { setEditingId(id); setHexDraft(hex.replace(/^#/, '')); };
  const commitEdit = id => {
    const v = CUp.normalizeHex(hexDraft);
    if (v) onEditHex(id, v);
    setEditingId(null); setHexDraft('');
  };
  const copyHex = hex => {
    navigator.clipboard?.writeText(hex);
    setCopied(hex);
    clearTimeout(copyTimer.current);
    copyTimer.current = setTimeout(() => setCopied(null), 1200);
  };

  return (
    <main className="palette-view">
      <div className="palette-toolbar">
        <button className="btn-primary sm" onClick={onGenerate}>
          <ShuffleIcon /> Generate
        </button>
        <span className="palette-space-hint">Press <kbd>Space</kbd></span>
      </div>
      <div className="palette-cols">
        {colors.map((c, i) => {
          const fgDark = CUp.contrastRatio(CUp.hexToRgb(c.hex), {r:0,g:0,b:0}) >
                         CUp.contrastRatio(CUp.hexToRgb(c.hex), {r:255,g:255,b:255});
          const txt       = fgDark ? 'rgba(0,0,0,.72)' : 'rgba(255,255,255,.88)';
          const isEditing = editingId === c.id;
          const isCopied  = copied === c.hex;
          return (
            <React.Fragment key={c.id}>
              <div className="palette-col" style={{ background: c.hex, color: txt }}>
                {c.locked && <div className="palette-lock-badge" style={{ color: txt }}><LockClosedIcon /></div>}

                <div className="palette-col-actions">
                  <button className="pal-btn" onClick={() => onToggleLock(c.id)}
                    title={c.locked ? 'Unlock' : 'Lock'} style={{ color: txt }}>
                    {c.locked ? <LockClosedIcon /> : <LockOpenIcon />}
                  </button>
                  <button className="pal-btn" onClick={() => copyHex(c.hex)}
                    title="Copy HEX" style={{ color: txt }}>
                    {isCopied ? <CheckIcon /> : <CopyIcon />}
                  </button>
                  {colors.length > 1 &&
                    <button className="pal-btn" onClick={() => onRemove(c.id)}
                      title="Remove" style={{ color: txt }}>
                      <CloseIcon />
                    </button>
                  }
                </div>

                {colors.length < 9 &&
                  <button className="palette-add-btn" onClick={() => onAddAt(i)} title="Add color">
                    <PlusIcon />
                  </button>
                }

                <div className="palette-col-label">
                  {isEditing ? (
                    <div className="palette-hex-edit" style={{ color: txt }}>
                      <span className="palette-hex-hash">#</span>
                      <input
                        className="palette-hex-input"
                        autoFocus
                        value={hexDraft}
                        onChange={e => setHexDraft(e.target.value.toUpperCase())}
                        onBlur={() => commitEdit(c.id)}
                        onKeyDown={e => {
                          if (e.key === 'Enter') commitEdit(c.id);
                          if (e.key === 'Escape') { setEditingId(null); setHexDraft(''); }
                        }}
                        maxLength={7}
                        spellCheck={false}
                        style={{ color: txt }}
                      />
                    </div>
                  ) : (
                    <button className="palette-hex-label" onClick={() => startEdit(c.id, c.hex)}
                      style={{ color: txt }}>
                      {c.hex.replace(/^#/, '')}
                    </button>
                  )}
                  <div className="palette-color-name" style={{ color: txt }}>{closestName(c.hex)}</div>
                </div>
              </div>
            </React.Fragment>
          );
        })}
      </div>
    </main>
  );
}

function ColorTabs({ colors, activeId, onSelect, onAdd, onRemove, onRename, hexInput, setHexInput, hexValid }) {
  const [editingId, setEditingId] = useStateC(null);
  return (
    <div className="color-tabs">
      <div className="color-tabs-list">
        {colors.map((c) => {
          const isActive = c.id === activeId;
          const isEditing = editingId === c.id;
          return (
            <div
              key={c.id}
              className={`color-tab ${isActive ? 'active' : ''}`}
              onClick={() => onSelect(c.id)}
              onDoubleClick={() => !isActive && setEditingId(c.id)}
>

              <span className="color-tab-sw" style={{ background: c.hex }} />
              {isEditing ?
              <input
                className="color-tab-name-input"
                autoFocus
                defaultValue={c.name}
                onBlur={(e) => { onRename(c.id, e.target.value || c.name); setEditingId(null); }}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') e.target.blur();
                  if (e.key === 'Escape') setEditingId(null);
                }}
                onClick={(e) => e.stopPropagation()} /> :
              <span
                className="color-tab-name"
                onDoubleClick={(e) => { e.stopPropagation(); setEditingId(c.id); }}>
                {c.name}
              </span>
              }
              {isActive ? (
                <div className={`color-tab-hex-wrap${hexValid ? '' : ' invalid'}`}
                  onClick={(e) => e.stopPropagation()}>
                  <span className="color-tab-hex-hash">#</span>
                  <input
                    className="color-tab-hex-input"
                    value={hexInput.replace(/^#/, '')}
                    onChange={(e) => setHexInput(e.target.value.toUpperCase())}
                    maxLength={7}
                    spellCheck={false}
                    placeholder="FF7700"
                  />
                </div>
              ) : (
                <span className="color-tab-hex">{c.hex}</span>
              )}
              {colors.length > 1 &&
              <button
                className="color-tab-x"
                onClick={(e) => { e.stopPropagation(); onRemove(c.id); }}
                aria-label="Remove">
                <CloseIcon />
              </button>
              }
            </div>);
        })}
      </div>
      <button className="color-tab-add" onClick={onAdd} aria-label="Add color">
        <PlusIcon /> Add color
      </button>
    </div>);
}

function LayoutSwitcher({ value, onChange }) {
  const opts = [
  { v: 'horizontal', label: 'Row', icon: <LayoutRowIcon /> },
  { v: 'vertical', label: 'Column', icon: <LayoutColIcon /> },
  { v: 'grid', label: 'Grid', icon: <LayoutGridIcon /> }];

  return (
    <div className="layout-switcher" role="tablist" aria-label="Layout">
      {opts.map((o) =>
      <button
        key={o.v}
        className={`layout-btn ${value === o.v ? 'active' : ''}`}
        onClick={() => onChange(o.v)}
        aria-label={o.label}
        title={o.label}>
        
          {o.icon}
          <span>{o.label}</span>
        </button>
      )}
    </div>);

}

function StepsControl({ value, onChange, basePos, onBasePosChange }) {
  const max = Math.max(0, value - 1);
  const pos = Math.max(0, Math.min(max, basePos));
  return (
    <div className="steps-control">
      <label>Steps</label>
      <div className="steps-input-wrap">
        <button className="steps-btn" onClick={() => onChange(Math.max(5, value - 1))}>−</button>
        <input
          type="number"
          min={5}
          max={50}
          value={value}
          onChange={(e) => {
            const n = parseInt(e.target.value, 10);
            if (!isNaN(n)) onChange(Math.max(5, Math.min(50, n)));
          }} />
        
        <button className="steps-btn" onClick={() => onChange(Math.min(50, value + 1))}>+</button>
      </div>
      <label className="steps-sep">Brand at</label>
      <div className="steps-input-wrap">
        <button className="steps-btn" onClick={() => onBasePosChange(Math.max(0, pos - 1))}>−</button>
        <input
          type="number"
          min={1}
          max={value}
          value={pos + 1}
          onChange={(e) => {
            const n = parseInt(e.target.value, 10);
            if (!isNaN(n)) onBasePosChange(Math.max(0, Math.min(max, n - 1)));
          }} />

        <button className="steps-btn" onClick={() => onBasePosChange(Math.min(max, pos + 1))}>+</button>
      </div>
      <span className="steps-posdisplay">of {value}</span>
    </div>);

}

function AlgoSegmented({ value, onChange }) {
  const opts = [
  { v: 'oklch', label: 'OKLCH', sub: 'perceptual' },
  { v: 'hsl', label: 'HSL', sub: 'lightness' },
  { v: 'mix', label: 'Mix', sub: 'white & black' }];

  return (
    <div className="segmented">
      {opts.map((o) =>
      <button
        key={o.v}
        className={`seg-btn ${value === o.v ? 'active' : ''}`}
        onClick={() => onChange(o.v)}>
        
          <span className="seg-label">{o.label}</span>
          <span className="seg-sub">{o.sub}</span>
        </button>
      )}
    </div>);

}

function TintControl({ value, onChange, lightHex, darkHex }) {
  return (
    <div className="tint-control">
      <div className="tint-head">
        <div>
          <div className="tint-title">Overlay strength</div>
          <div className="tint-sub">
            Opacity of the source color over the white→black ramp
          </div>
        </div>
        <div className="tint-val">{Math.round(value * 100)}%</div>
      </div>
      <div className="tint-row">
        <div className="tint-end">
          <span className="tint-end-sw" style={{ background: lightHex }} />
          <span className="tint-end-hex">{lightHex}</span>
        </div>
        <input
          className="tint-slider"
          type="range"
          min={0} max={1} step={0.01}
          value={value}
          onChange={(e) => onChange(parseFloat(e.target.value))}
          style={{ '--tint-pct': `${value * 100}%` }} />
        
        <div className="tint-end dark">
          <span className="tint-end-sw" style={{ background: darkHex }} />
          <span className="tint-end-hex">{darkHex}</span>
        </div>
      </div>
    </div>);

}

function ShadeStrip({ shades, baseHex, selectedIdx, onSelect, onCopy, onDetails, copiedTag, showLabels, layout = 'horizontal' }) {
  // find the shade closest to the base
  const baseIdx = React.useMemo(() => {
    const baseRgb = CUc.hexToRgb(baseHex);
    const baseOk = CUc.rgbToOklab(baseRgb);
    let best = 0,bestD = Infinity;
    shades.forEach((s, i) => {
      const o = CUc.rgbToOklab(s.rgb);
      const d = (o.L - baseOk.L) ** 2 + (o.a - baseOk.a) ** 2 + (o.b - baseOk.b) ** 2;
      if (d < bestD) {bestD = d;best = i;}
    });
    return best;
  }, [shades, baseHex]);

  return (
    <div className={`strip-wrap layout-${layout}`}>
      <div className={`strip strip-${layout}`} style={{ '--tile-count': shades.length }}>
        {shades.map((s, i) => {
          const fgDark = CUc.contrastRatio(s.rgb, { r: 0, g: 0, b: 0 }) >
          CUc.contrastRatio(s.rgb, { r: 255, g: 255, b: 255 });
          const txt = fgDark ? 'rgba(0,0,0,.78)' : 'rgba(255,255,255,.92)';
          const isBase = i === baseIdx;
          const isSel = i === selectedIdx;
          const isCopied = copiedTag === `strip-${i}`;
          return (
            <div
              key={i}
              className={`tile ${isSel ? 'selected' : ''} ${isBase ? 'base' : ''}`}
              style={{ background: s.hex, color: txt }}
              onClick={() => onCopy(s, i)}>
              
              {isBase && <span className="tile-base-dot" style={{ background: txt }} />}
              <div className="tile-top">
                <span className="tile-idx">{String(i + 1).padStart(2, '0')}</span>
                <button
                  className="tile-dots"
                  onClick={(e) => {e.stopPropagation();onDetails(i);}}
                  aria-label="Details"
                  style={{ color: txt }}>
                  
                  <DotsIcon />
                </button>
              </div>
              {showLabels &&
              <div className="tile-bot">
                  <span className="tile-hex">{s.hex}</span>
                  {isCopied && <span className="tile-copied">Copied</span>}
                </div>
              }
              {!showLabels && isCopied &&
              <div className="tile-bot"><span className="tile-copied">Copied</span></div>
              }
            </div>);

        })}
      </div>
      <div className="strip-axis">
        <span>Lightest</span>
        <span>Base</span>
        <span>Darkest</span>
      </div>
    </div>);

}

function SelectedCard({ shade, idx, onCopy, copiedTag, onDetails }) {
  if (!shade) {
    return (
      <div className="selected-card empty">
        <div className="sc-hint">Click any tile to inspect its values.</div>
      </div>);

  }
  const hsl = CUc.rgbToHsl(shade.rgb);
  const oklch = CUc.rgbToOklch(shade.rgb);
  const fields = [
  { k: 'HEX', v: shade.hex, copy: shade.hex },
  { k: 'RGB', v: fmtRgbC(shade.rgb), copy: fmtRgbC(shade.rgb) },
  { k: 'HSL', v: fmtHslC(hsl), copy: fmtHslC(hsl) },
  { k: 'OKLCH', v: fmtOklchC(oklch), copy: fmtOklchC(oklch) }];

  return (
    <div className="selected-card">
      <div className="sc-swatch" style={{ background: shade.hex }} />
      <div className="sc-body">
        <div className="sc-head">
          <div>
            <div className="sc-label">Stop {idx + 1}</div>
            <div className="sc-hex">{shade.hex}</div>
          </div>
          <button className="btn-ghost sm" onClick={onDetails}>All formats →</button>
        </div>
        <div className="sc-fields">
          {fields.map((f) => {
            const tag = `sc-${f.k}`;
            return (
              <button
                key={f.k}
                className="sc-field"
                onClick={() => onCopy(f.copy, tag)}>
                
                <span className="sc-k">{f.k}</span>
                <span className="sc-v">{f.v}</span>
                <span className="sc-ico">
                  {copiedTag === tag ? <CheckIcon /> : <CopyIcon />}
                </span>
              </button>);

          })}
        </div>
      </div>
    </div>);

}

const fmtHslC = (h) => `hsl(${Math.round(h.h)}, ${Math.round(h.s)}%, ${Math.round(h.l)}%)`;
const fmtRgbC = (r) => `rgb(${Math.round(r.r)}, ${Math.round(r.g)}, ${Math.round(r.b)})`;
const fmtOklchC = (o) => `oklch(${(o.L * 100).toFixed(1)}% ${o.C.toFixed(3)} ${o.H.toFixed(1)})`;
const fmtCmykC = (c) => `cmyk(${Math.round(c.c)}%, ${Math.round(c.m)}%, ${Math.round(c.y)}%, ${Math.round(c.k)}%)`;

// ─── Tints Panel ───────────────────────────────────────────
function TintsPanel({
  sourceHex, sourceLabel, sourceIsSelected,
  algorithm, tint, steps,
  onStepsChange, onTintChange,
  onCopy, copiedTag, showLabels,
  layout = 'horizontal', onLayoutChange
}) {
  const tintShades = React.useMemo(
    () => CUc.generateTints(sourceHex, steps, tint),
    [sourceHex, steps, tint]
  );

  return (
    <section className="panel tints-panel">
      <div className="panel-head">
        <div>
          <h2 className="h-title">Tints
            <span className={`tints-source ${sourceIsSelected ? 'is-selected' : ''}`}>
              <span className="tints-source-sw" style={{ background: sourceHex }} />
              <span className="tints-source-hex">{sourceHex}</span>
            </span>
          </h2>
        </div>
        <div className="tints-head-actions">
          <LayoutSwitcher value={layout} onChange={onLayoutChange} />
          <div className="tints-steps">
          <label>Steps</label>
          <div className="steps-input-wrap">
            <button className="steps-btn" onClick={() => onStepsChange(Math.max(3, steps - 1))}>−</button>
            <input
              type="number"
              min={3}
              max={24}
              value={steps}
              onChange={(e) => {
                const n = parseInt(e.target.value, 10);
                if (!isNaN(n)) onStepsChange(Math.max(3, Math.min(24, n)));
              }} />
            
            <button className="steps-btn" onClick={() => onStepsChange(Math.min(24, steps + 1))}>+</button>
          </div>
          </div>
        </div>
      </div>

      <TintControl
        value={tint}
        onChange={onTintChange}
        lightHex={tintShades[0]?.hex || '#FFFFFF'}
        darkHex={tintShades[tintShades.length - 1]?.hex || '#000000'} />
      

      <div className={`tints-grid tints-layout-${layout}`} style={{ '--tcount': steps }}>
        {tintShades.map((s, i) => {
          const fgDark = CUc.contrastRatio(s.rgb, { r: 0, g: 0, b: 0 }) >
          CUc.contrastRatio(s.rgb, { r: 255, g: 255, b: 255 });
          const txt = fgDark ? 'rgba(0,0,0,.78)' : 'rgba(255,255,255,.92)';
          const tag = `tint-${i}`;
          const isCopied = copiedTag === tag;
          return (
            <button
              key={i}
              className="tint-tile"
              style={{ background: s.hex, color: txt }}
              onClick={() => onCopy(s.hex, tag)}
              title={`Copy ${s.hex}`}>

              <span className="tint-tile-idx">{String(i + 1).padStart(2, '0')}</span>
              {showLabels && <span className="tint-tile-hex">{s.hex}</span>}
              {isCopied && <span className="tint-tile-copied">Copied</span>}
            </button>);

        })}
      </div>
    </section>);

}

// ─── UI Check view ────────────────────────────────────────────────────────
function UICheckView({ colors, activeId, onSelect, onAdd, onRemove, onRename,
                       hexInput, setHexInput, hexValid, dark, tweaks }) {
  const CUp = window.ColorUtil;
  const active = colors.find(c => c.id === activeId) || colors[0];
  const shades = React.useMemo(
    () => CUp.generateShades(active.hex, tweaks.steps, tweaks.algorithm, tweaks.tint, tweaks.basePos),
    [active.hex, tweaks.steps, tweaks.algorithm, tweaks.tint, tweaks.basePos]
  );
  return (
    <main className="ui-check-view">
      <ColorTabs
        colors={colors}
        activeId={activeId}
        onSelect={onSelect}
        onAdd={onAdd}
        onRemove={onRemove}
        onRename={onRename}
        hexInput={hexInput}
        setHexInput={setHexInput}
        hexValid={hexValid}
      />
      <UIPreview shades={shades} baseHex={active.hex} dark={dark} />
    </main>
  );
}

// ─── icons ────────────────────────────────────────────────────────────────
const Svg = (p) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p} />;
const MoonIcon = () => <Svg><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /></Svg>;
const SunIcon = () => <Svg><circle cx="12" cy="12" r="4" /><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" /></Svg>;
const ExportIcon = () => <Svg><path d="M12 3v12" /><path d="m7 8 5-5 5 5" /><path d="M5 21h14" /></Svg>;
const DotsIcon = () => <Svg><circle cx="5" cy="12" r="1.2" fill="currentColor" /><circle cx="12" cy="12" r="1.2" fill="currentColor" /><circle cx="19" cy="12" r="1.2" fill="currentColor" /></Svg>;
const CopyIcon = () => <Svg><rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" /></Svg>;
const CheckIcon = () => <Svg><path d="m5 12 5 5L20 7" /></Svg>;
const CloseIcon = () => <Svg><path d="M18 6 6 18M6 6l12 12" /></Svg>;
const ChevronL = () => <Svg><path d="m15 18-6-6 6-6" /></Svg>;
const ChevronR = () => <Svg><path d="m9 18 6-6-6-6" /></Svg>;
const PlusIcon = () => <Svg><path d="M12 5v14M5 12h14" /></Svg>;
const LayoutRowIcon = () => <Svg><rect x="3" y="9" width="18" height="6" rx="1.2" /><path d="M9 9v6M15 9v6" /></Svg>;
const LayoutColIcon = () => <Svg><rect x="9" y="3" width="6" height="18" rx="1.2" /><path d="M9 9h6M9 15h6" /></Svg>;
const LayoutGridIcon = () => <Svg><rect x="3" y="3" width="7" height="7" rx="1.2" /><rect x="14" y="3" width="7" height="7" rx="1.2" /><rect x="3" y="14" width="7" height="7" rx="1.2" /><rect x="14" y="14" width="7" height="7" rx="1.2" /></Svg>;
const ShuffleIcon = () => <Svg><path d="M2 18h4l10-12h4" /><path d="M16 18h4v-4" /><path d="M2 6h4l3 3.5" /><path d="M16 6h4v4" /></Svg>;
const LockClosedIcon = () => <Svg><rect x="5" y="11" width="14" height="10" rx="2" /><path d="M8 11V7a4 4 0 0 1 8 0v4" /></Svg>;
const LockOpenIcon = () => <Svg><rect x="5" y="11" width="14" height="10" rx="2" /><path d="M8 11V7a4 4 0 0 1 7.92-.64" /></Svg>;

Object.assign(window, {
  TopBar, ColorTabs, LayoutSwitcher, StepsControl, AlgoSegmented, TintControl, TintsPanel, ShadeStrip, SelectedCard, PaletteView, UICheckView,
  MoonIcon, SunIcon, ExportIcon, DotsIcon, CopyIcon, CheckIcon, CloseIcon, ChevronL, ChevronR,
  PlusIcon, LayoutRowIcon, LayoutColIcon, LayoutGridIcon,
  ShuffleIcon, LockClosedIcon, LockOpenIcon,
  fmtHslC, fmtRgbC, fmtOklchC, fmtCmykC
});