/* global React, ReactDOM, lucide */
/* ============================================================
   App — router + tweaks + page dispatch + per-route metadata
   ============================================================ */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "beamIntensity": 0.55,
  "spacingDensity": "regular",
  "typeScale": "regular",
  "atmosphere": "regular",
  "motion": "restrained",
  "asymmetry": "asymmetric",
  "diagnosticPacing": "measured",
  "imageOpacity": 0.95,
  "editorialDensity": "regular"
}/*EDITMODE-END*/;

/* ============================================================
   Per-route metadata
   ============================================================ */
const SITE_NAME = 'The Daniel Pledger';
const SITE_BASE_URL = 'https://thedanielpledger.com'; // placeholder canonical origin

const ROUTE_META = {
  '/': {
    title: 'The Daniel Pledger — Identity Holding Under Pressure',
    desc: 'Private executive authority advisory. For senior leaders who have outgrown the performance and need their signal to carry when the room is loudest.',
  },
  '/audit': {
    title: 'The Executive Authority Signal Audit — The Daniel Pledger',
    desc: 'A private diagnostic for senior leaders. Ten questions. A short reading of where authority leaks under consequence.',
  },
  '/audit/flow': {
    title: 'The Audit — In progress — The Daniel Pledger',
    desc: 'The Executive Authority Signal Audit. Held in confidence.',
  },
  '/audit/results': {
    title: 'The Reading — The Executive Authority Signal Audit',
    desc: 'Your private reading. One dominant signature. One secondary. Held in confidence.',
  },
  '/conversation': {
    title: 'Request a Private Conversation — The Daniel Pledger',
    desc: 'A short note about the room you are trying to hold is usually enough. Daniel responds personally within a week.',
  },
  '/coaching': {
    title: 'Executive Coaching — The Daniel Pledger',
    desc: 'Private 1:1 executive coaching for senior leaders. Intake form and discovery call to explore fit.',
  },
  '/insights': {
    title: 'Field Notes — The Daniel Pledger',
    desc: 'Short, deliberate writing on identity, authority, and what the senior room actually reads.',
  },
  '/perspective': {
    title: 'Perspective — The Daniel Pledger',
    desc: 'I do not coach performance. I work on identity. A position on what private executive advisory is, and is not.',
  },
  '/speaking': {
    title: 'Speaking — The Daniel Pledger',
    desc: 'Closed-room conversations on authority under consequence. Founder cohorts, board offsites, leadership intensives.',
  },
  '/privacy': {
    title: 'Privacy Policy — The Daniel Pledger',
    desc: 'What is collected when you use this site, why, and how it is held.',
  },
  '/terms': {
    title: 'Terms of Service — The Daniel Pledger',
    desc: 'The terms that apply to this site, its writing, and the Executive Authority Signal Audit.',
  },
};

function getRouteMeta(path) {
  if (ROUTE_META[path]) return ROUTE_META[path];
  // /insights/:slug
  const m = matchRoute(path, '/insights/:slug');
  if (m) {
    const i = (window.INSIGHTS || []).find((x) => x.slug === m.slug);
    if (i) {
      return {
        title: `${i.title} — The Daniel Pledger`,
        desc: i.excerpt,
      };
    }
  }
  return {
    title: SITE_NAME,
    desc: ROUTE_META['/'].desc,
  };
}

/* Update <title> and meta tags imperatively for SPA route changes */
function applyRouteMeta(path) {
  const meta = getRouteMeta(path);
  const canonical = SITE_BASE_URL + path;

  document.title = meta.title;
  setMeta('description', meta.desc);

  // Open Graph
  setMetaProperty('og:title', meta.title);
  setMetaProperty('og:description', meta.desc);
  setMetaProperty('og:type', 'website');
  setMetaProperty('og:site_name', SITE_NAME);
  setMetaProperty('og:url', canonical);
  setMetaProperty('og:image', SITE_BASE_URL + '/og-default.jpg');

  // Twitter
  setMeta('twitter:card', 'summary_large_image');
  setMeta('twitter:title', meta.title);
  setMeta('twitter:description', meta.desc);
  setMeta('twitter:image', SITE_BASE_URL + '/og-default.jpg');

  // Canonical
  setLink('canonical', canonical);
}

function setMeta(name, content) {
  let el = document.querySelector(`meta[name="${name}"]`);
  if (!el) { el = document.createElement('meta'); el.setAttribute('name', name); document.head.appendChild(el); }
  el.setAttribute('content', content || '');
}
function setMetaProperty(prop, content) {
  let el = document.querySelector(`meta[property="${prop}"]`);
  if (!el) { el = document.createElement('meta'); el.setAttribute('property', prop); document.head.appendChild(el); }
  el.setAttribute('content', content || '');
}
function setLink(rel, href) {
  let el = document.querySelector(`link[rel="${rel}"]`);
  if (!el) { el = document.createElement('link'); el.setAttribute('rel', rel); document.head.appendChild(el); }
  el.setAttribute('href', href);
}

/* ============================================================
   Map tweak values to CSS variables on :root
   ============================================================ */
function applyTweaksToRoot(t) {
  const r = document.documentElement;
  r.style.setProperty('--tdp-beam', String(t.beamIntensity));

  const dens = { compact: 0.72, regular: 1.0, generous: 1.35 }[t.spacingDensity] || 1;
  r.style.setProperty('--tdp-density', String(dens));

  const ts = { smaller: 0.88, regular: 1.0, larger: 1.12 }[t.typeScale] || 1;
  r.style.setProperty('--tdp-type-scale', String(ts));

  const mo = { still: 0, restrained: 1.0, lively: 1.6 }[t.motion] || 1;
  r.style.setProperty('--tdp-motion', String(mo));

  r.style.setProperty('--tdp-img-opacity', String(t.imageOpacity));

  const ed = { sparse: 0.86, regular: 1.0, dense: 1.16 }[t.editorialDensity] || 1;
  r.style.setProperty('--tdp-edit-density', String(ed));

  const atm = {
    lighter:  { bg: 'var(--c-admiral-ink)',     deep: 'var(--c-imperial-indigo)' },
    regular:  { bg: 'var(--c-imperial-indigo)', deep: 'var(--c-nightfall)' },
    deeper:   { bg: 'var(--c-nightfall)',       deep: '#06080d' },
  }[t.atmosphere] || { bg: 'var(--c-imperial-indigo)', deep: 'var(--c-nightfall)' };
  document.body.style.background = atm.bg;
  r.style.setProperty('--bg', atm.bg);
  r.style.setProperty('--bg-deep', atm.deep);
}

/* ============================================================
   Page dispatcher — reads router path, applies metadata
   ============================================================ */
function Page() {
  const { path } = useRouter();

  // Apply per-route metadata on every path change
  React.useEffect(() => { applyRouteMeta(path); }, [path]);

  if (path === '/' || path === '') return <HomePage />;
  if (path === '/audit') return <AuditLandingPage />;
  if (path === '/audit/flow') return <AuditFlowPage />;
  if (path === '/audit/results') return <AuditResultsPage />;
  if (path === '/conversation') return <ConversationPage />;
  if (path === '/coaching') return <CoachingPage />;
  if (path === '/insights') return <InsightsIndexPage />;
  const m = matchRoute(path, '/insights/:slug');
  if (m) return <InsightArticlePage slug={m.slug} />;
  if (path === '/perspective') return <PerspectivePage />;
  if (path === '/speaking') return <SpeakingPage />;
  if (path === '/privacy') return <PrivacyPage />;
  if (path === '/terms') return <TermsPage />;

  return (
    <div className="page-fade">
      <section style={{ paddingTop: 200, minHeight: '80vh' }}>
        <div className="container-narrow" style={{ textAlign: 'center' }}>
          <Eyebrow>Off the map</Eyebrow>
          <h1 style={{ fontSize: 'clamp(36px, 4vw, 64px)', color: '#fff', fontWeight: 500, margin: '24px 0 24px', letterSpacing: '-0.028em' }}>
            This path does not lead anywhere.
          </h1>
          <Button variant="primary" href="/">Return home</Button>
        </div>
      </section>
    </div>
  );
}

/* ============================================================
   Tweaks UI
   ============================================================ */
function TweaksPanelTDP({ tweaks, setTweak }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Atmosphere">
        <TweakSlider
          label="Beam intensity"
          value={tweaks.beamIntensity}
          min={0.1} max={1.0} step={0.05}
          onChange={(v) => setTweak('beamIntensity', v)}
        />
        <TweakSelect
          label="Atmospheric contrast"
          value={tweaks.atmosphere}
          options={[
            { value: 'lighter', label: 'Lighter' },
            { value: 'regular', label: 'Regular' },
            { value: 'deeper',  label: 'Deeper' },
          ]}
          onChange={(v) => setTweak('atmosphere', v)}
        />
        <TweakSlider
          label="Image luminance"
          value={tweaks.imageOpacity}
          min={0.3} max={1.0} step={0.05}
          onChange={(v) => setTweak('imageOpacity', v)}
        />
      </TweakSection>

      <TweakSection label="Layout">
        <TweakRadio
          label="Density"
          value={tweaks.spacingDensity}
          options={['compact', 'regular', 'generous']}
          onChange={(v) => setTweak('spacingDensity', v)}
        />
        <TweakRadio
          label="Asymmetry"
          value={tweaks.asymmetry}
          options={['centered', 'balanced', 'asymmetric']}
          onChange={(v) => setTweak('asymmetry', v)}
        />
        <TweakRadio
          label="Editorial density"
          value={tweaks.editorialDensity}
          options={['sparse', 'regular', 'dense']}
          onChange={(v) => setTweak('editorialDensity', v)}
        />
      </TweakSection>

      <TweakSection label="Type">
        <TweakRadio
          label="Type scale"
          value={tweaks.typeScale}
          options={['smaller', 'regular', 'larger']}
          onChange={(v) => setTweak('typeScale', v)}
        />
      </TweakSection>

      <TweakSection label="Motion">
        <TweakRadio
          label="Motion restraint"
          value={tweaks.motion}
          options={['still', 'restrained', 'lively']}
          onChange={(v) => setTweak('motion', v)}
        />
        <TweakRadio
          label="Diagnostic pacing"
          value={tweaks.diagnosticPacing}
          options={['quick', 'measured', 'slow']}
          onChange={(v) => setTweak('diagnosticPacing', v)}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

/* ============================================================
   Root
   ============================================================ */
function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Apply tweaks to :root variables
  React.useEffect(() => { applyTweaksToRoot(tweaks); }, [tweaks]);

  // Lucide icon refresh
  React.useEffect(() => {
    const id = setTimeout(() => window.lucide && window.lucide.createIcons(), 60);
    return () => clearTimeout(id);
  });
  React.useEffect(() => {
    const i = setInterval(() => window.lucide && window.lucide.createIcons(), 800);
    return () => clearInterval(i);
  }, []);

  return (
    <RouterProvider>
      <TweaksContext.Provider value={tweaks}>
        <a href="#main-content" className="skip-link">Skip to content</a>
        <Nav />
        <main id="main-content" tabIndex={-1} style={{ position: 'relative', overflow: 'hidden' }}>
          <Page />
        </main>
        <Footer />
        <TweaksPanelTDP tweaks={tweaks} setTweak={setTweak} />
      </TweaksContext.Provider>
    </RouterProvider>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

// expose INSIGHTS to window so getRouteMeta can resolve article titles
// (pages-insights.jsx attaches INSIGHTS to window already)
