// tweaks-app.jsx
// Tweaks application for the Cafe Mock home page.
// All adjustable values flow through CSS custom properties on :root,
// set via document.documentElement.style.setProperty().

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "classic",
  "bgColor": "#FBF7F0",
  "textColor": "#2A2620",
  "headingColor": "#1A1714",
  "accentColor": "#8C6A4A",
  "ruleColor": "#E2D9C8",
  "footerBgColor": "#1A1714",

  "fontPair": "serif-sans",
  "baseSize": 16,
  "headingWeight": 500,
  "headingTracking": -2,
  "logoTracking": 28,

  "contentWidth": 1100,
  "sectionPad": 6,
  "radius": 6,

  "heroHeight": 560,
  "heroMono": 0,
  "heroDark": 32,
  "heroAlign": "center",
  "heroKicker": "Quiet hours, slow coffee",
  "heroTitle": "ゆっくりとした時間を、\nあなたに。",
  "heroSub": "光と静けさを大切にした、街角の小さなカフェ。一杯のコーヒーから、午後の読書まで。",

  "menuRule": "dotted",
  "menuLineHeight": 2.2,
  "menuCardOpacity": 0.92
}/*EDITMODE-END*/;

// ── Palette presets ─────────────────────────────────────────────────────────
const PALETTES = {
  classic: {
    bgColor: "#FBF7F0",
    textColor: "#2A2620",
    headingColor: "#1A1714",
    accentColor: "#8C6A4A",
    ruleColor: "#E2D9C8",
    footerBgColor: "#1A1714",
  },
  cream: {
    bgColor: "#F5EFE3",
    textColor: "#3A3024",
    headingColor: "#221C12",
    accentColor: "#B5793F",
    ruleColor: "#DDD0B8",
    footerBgColor: "#221C12",
  },
  mist: {
    bgColor: "#F2F2EE",
    textColor: "#2C2E2A",
    headingColor: "#15171A",
    accentColor: "#5C7A86",
    ruleColor: "#D8DAD2",
    footerBgColor: "#15171A",
  },
  moss: {
    bgColor: "#EFEDE3",
    textColor: "#262922",
    headingColor: "#101411",
    accentColor: "#5C6B3F",
    ruleColor: "#D2D2BD",
    footerBgColor: "#1B1F18",
  },
  dark: {
    bgColor: "#1A1714",
    textColor: "#D8CFBF",
    headingColor: "#F2EBDB",
    accentColor: "#C99A6B",
    ruleColor: "#3A322A",
    footerBgColor: "#0F0D0B",
  },
};

const FONT_PAIRS = {
  "serif-sans": {
    body: "'Inter', system-ui, -apple-system, sans-serif",
    heading: "'Fraunces', 'Shippori Mincho', serif",
    label: "'Inter', system-ui, sans-serif",
  },
  "serif": {
    body: "'Fraunces', 'Shippori Mincho', Georgia, serif",
    heading: "'Fraunces', 'Shippori Mincho', serif",
    label: "'Fraunces', Georgia, serif",
  },
  "sans": {
    body: "'Inter', system-ui, -apple-system, sans-serif",
    heading: "'Inter', system-ui, sans-serif",
    label: "'Inter', system-ui, sans-serif",
  },
  "mincho": {
    body: "'Shippori Mincho', 'Fraunces', serif",
    heading: "'Shippori Mincho', 'Fraunces', serif",
    label: "'Shippori Mincho', serif",
  },
};

// ── Apply a tweak object to CSS custom properties ───────────────────────────
function applyTweaksToCss(t) {
  const r = document.documentElement;
  // Colors
  r.style.setProperty('--bg', t.bgColor);
  r.style.setProperty('--text', t.textColor);
  r.style.setProperty('--heading', t.headingColor);
  r.style.setProperty('--accent', t.accentColor);
  r.style.setProperty('--rule', t.ruleColor);
  r.style.setProperty('--footer-bg', t.footerBgColor);
  r.style.setProperty('--footer-text', mix(t.footerBgColor, '#ffffff', 0.78));
  r.style.setProperty('--surface', mix(t.bgColor, '#ffffff', 0.4));
  r.style.setProperty('--muted', mix(t.textColor, t.bgColor, 0.45));

  // Fonts
  const f = FONT_PAIRS[t.fontPair] || FONT_PAIRS["serif-sans"];
  r.style.setProperty('--font-body', f.body);
  r.style.setProperty('--font-heading', f.heading);
  r.style.setProperty('--font-label', f.label);
  r.style.setProperty('--base-size', t.baseSize + 'px');
  r.style.setProperty('--h-weight', String(t.headingWeight));
  r.style.setProperty('--h-track', (t.headingTracking / 100) + 'em');
  r.style.setProperty('--logo-track', (t.logoTracking / 100) + 'em');

  // Layout
  r.style.setProperty('--content-w', t.contentWidth + 'px');
  r.style.setProperty('--sect-pad', t.sectionPad + 'rem');
  r.style.setProperty('--radius', t.radius + 'px');

  // Hero
  r.style.setProperty('--hero-h', t.heroHeight + 'px');
  r.style.setProperty('--hero-mono', (t.heroMono / 100));
  r.style.setProperty('--hero-dark', (t.heroDark / 100));
  const align = t.heroAlign === 'top' ? 'flex-start' : t.heroAlign === 'bottom' ? 'flex-end' : 'center';
  r.style.setProperty('--hero-align', align);

  // Menu
  r.style.setProperty('--menu-rule', t.menuRule === 'none' ? 'transparent' : t.ruleColor);
  r.style.setProperty('--menu-rule-style', t.menuRule === 'none' ? 'solid' : t.menuRule);
  r.style.setProperty('--menu-lh', String(t.menuLineHeight));
  r.style.setProperty('--card-opacity', String(t.menuCardOpacity));
}

// Simple hex mix (for derived footer text / muted colors).
function mix(hexA, hexB, w) {
  const a = parseHex(hexA), b = parseHex(hexB);
  const r = Math.round(a[0] * (1 - w) + b[0] * w);
  const g = Math.round(a[1] * (1 - w) + b[1] * w);
  const bl = Math.round(a[2] * (1 - w) + b[2] * w);
  return `rgb(${r},${g},${bl})`;
}
function parseHex(h) {
  let s = h.replace('#', '');
  if (s.length === 3) s = s.split('').map(c => c + c).join('');
  return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)];
}

// ── App ─────────────────────────────────────────────────────────────────────
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Apply on every change
  React.useEffect(() => { applyTweaksToCss(t); }, [t]);

  // Mirror text edits into the live DOM (no re-render needed for the page)
  React.useEffect(() => {
    const k = document.querySelector('[data-bind="hero-kicker"]');
    if (k) k.textContent = t.heroKicker;
    const ti = document.querySelector('[data-bind="hero-title"]');
    if (ti) ti.innerHTML = formatHeroTitle(t.heroTitle);
    const s = document.querySelector('[data-bind="hero-sub"]');
    if (s) s.textContent = t.heroSub;
  }, [t.heroKicker, t.heroTitle, t.heroSub]);

  // Apply palette preset (write all six color keys at once)
  const setPalette = (name) => {
    const p = PALETTES[name];
    if (!p) return;
    setTweak({ palette: name, ...p });
  };

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Palette" />
      <TweakRadio
        label="Preset"
        value={t.palette}
        options={[
          { value: 'classic', label: 'Classic' },
          { value: 'cream', label: 'Cream' },
          { value: 'mist', label: 'Mist' },
          { value: 'moss', label: 'Moss' },
          { value: 'dark', label: 'Dark' },
        ]}
        onChange={setPalette}
      />
      <TweakColor label="Background" value={t.bgColor}
        onChange={(v) => setTweak({ bgColor: v, palette: 'custom' })} />
      <TweakColor label="Body text" value={t.textColor}
        onChange={(v) => setTweak({ textColor: v, palette: 'custom' })} />
      <TweakColor label="Heading" value={t.headingColor}
        onChange={(v) => setTweak({ headingColor: v, palette: 'custom' })} />
      <TweakColor label="Accent" value={t.accentColor}
        onChange={(v) => setTweak({ accentColor: v, palette: 'custom' })} />
      <TweakColor label="Rule" value={t.ruleColor}
        onChange={(v) => setTweak({ ruleColor: v, palette: 'custom' })} />
      <TweakColor label="Footer bg" value={t.footerBgColor}
        onChange={(v) => setTweak({ footerBgColor: v, palette: 'custom' })} />

      <TweakSection label="Typography" />
      <TweakRadio
        label="Pairing"
        value={t.fontPair}
        options={[
          { value: 'serif-sans', label: 'Serif+Sans' },
          { value: 'serif', label: 'Serif' },
          { value: 'sans', label: 'Sans' },
          { value: 'mincho', label: '明朝' },
        ]}
        onChange={(v) => setTweak('fontPair', v)}
      />
      <TweakSlider label="Base size" value={t.baseSize} min={13} max={20} unit="px"
        onChange={(v) => setTweak('baseSize', v)} />
      <TweakSlider label="Heading weight" value={t.headingWeight} min={300} max={700} step={100}
        onChange={(v) => setTweak('headingWeight', v)} />
      <TweakSlider label="Heading tracking" value={t.headingTracking} min={-3} max={15} unit="/100em"
        onChange={(v) => setTweak('headingTracking', v)} />
      <TweakSlider label="Logo tracking" value={t.logoTracking} min={0} max={80} unit="/100em"
        onChange={(v) => setTweak('logoTracking', v)} />

      <TweakSection label="Layout" />
      <TweakSlider label="Content width" value={t.contentWidth} min={720} max={1280} step={10} unit="px"
        onChange={(v) => setTweak('contentWidth', v)} />
      <TweakSlider label="Section padding" value={t.sectionPad} min={3} max={12} step={0.5} unit="rem"
        onChange={(v) => setTweak('sectionPad', v)} />
      <TweakSlider label="Corner radius" value={t.radius} min={0} max={28} unit="px"
        onChange={(v) => setTweak('radius', v)} />

      <TweakSection label="Hero" />
      <TweakSlider label="Height" value={t.heroHeight} min={320} max={820} step={10} unit="px"
        onChange={(v) => setTweak('heroHeight', v)} />
      <TweakSlider label="Monochrome" value={t.heroMono} min={0} max={100} unit="%"
        onChange={(v) => setTweak('heroMono', v)} />
      <TweakSlider label="Darkness" value={t.heroDark} min={0} max={75} unit="%"
        onChange={(v) => setTweak('heroDark', v)} />
      <TweakRadio label="Copy position" value={t.heroAlign}
        options={[
          { value: 'top', label: 'Top' },
          { value: 'center', label: 'Mid' },
          { value: 'bottom', label: 'Btm' },
        ]}
        onChange={(v) => setTweak('heroAlign', v)} />
      <TweakText label="Kicker" value={t.heroKicker}
        onChange={(v) => setTweak('heroKicker', v)} />
      <TweakText label="Title" value={t.heroTitle.replace(/\n/g, ' / ')}
        onChange={(v) => setTweak('heroTitle', v.replace(/ \/ /g, '\n'))} />
      <TweakText label="Subcopy" value={t.heroSub}
        onChange={(v) => setTweak('heroSub', v)} />

      <TweakSection label="Menu" />
      <TweakRadio label="Divider" value={t.menuRule}
        options={[
          { value: 'dotted', label: '······' },
          { value: 'dashed', label: '─ ─' },
          { value: 'solid', label: '———' },
          { value: 'none', label: 'None' },
        ]}
        onChange={(v) => setTweak('menuRule', v)} />
      <TweakSlider label="Line height" value={t.menuLineHeight} min={1.4} max={3.2} step={0.05}
        onChange={(v) => setTweak('menuLineHeight', v)} />
      <TweakSlider label="Card opacity" value={t.menuCardOpacity} min={0.4} max={1} step={0.02}
        onChange={(v) => setTweak('menuCardOpacity', v)} />
    </TweaksPanel>
  );
}

// Hero title supports newlines and *italic* spans wrapped in <em>.
// We use the convention: text between *…* becomes <em>.
function formatHeroTitle(s) {
  const escaped = s
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
  const withEm = escaped.replace(/\*([^*]+)\*/g, '<em>$1</em>');
  return withEm.replace(/\n/g, '<br>');
}

// Apply defaults synchronously so the page paints with the right colors
// before React mounts (avoids a flash of un-tweaked styles).
applyTweaksToCss(TWEAK_DEFAULTS);

// Also propagate the initial hero copy.
document.addEventListener('DOMContentLoaded', () => {
  const k = document.querySelector('[data-bind="hero-kicker"]');
  if (k) k.textContent = TWEAK_DEFAULTS.heroKicker;
  const ti = document.querySelector('[data-bind="hero-title"]');
  if (ti) ti.innerHTML = formatHeroTitle(TWEAK_DEFAULTS.heroTitle);
  const s = document.querySelector('[data-bind="hero-sub"]');
  if (s) s.textContent = TWEAK_DEFAULTS.heroSub;
});

const root = ReactDOM.createRoot(document.getElementById('tweaks-root'));
root.render(<App />);
