/* === App: router + tweaks + content === */

// Clean-path routing (no #/ in URLs). The route is the pathname.
// Backward-compat: any legacy `#/path?query` hash (old bookmarks/links and the
// Stripe payment-link redirects that still point at /#/share etc.) is rewritten
// to the clean `/path?query` on load, preserving the query (e.g. session_id).
function normalizeLegacyHash() {
  const h = window.location.hash;
  if (h && h.indexOf('#/') === 0) {
    const clean = h.slice(1) || '/'; // '#/share?x' -> '/share?x'
    try { window.history.replaceState(null, '', clean); } catch (_) {}
    return true;
  }
  return false;
}
const routeFromPath = () => {
  const p = window.location.pathname || '/';
  return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p; // trim trailing slash
};

// Programmatic SPA navigation (replaces `window.location.hash = ...`).
window.navigate = (to) => {
  try { window.history.pushState(null, '', to); } catch (_) {}
  window.dispatchEvent(new PopStateEvent('popstate'));
};

const useRoute = () => {
  const [route, setRoute] = React.useState(() => { normalizeLegacyHash(); return routeFromPath(); });
  React.useEffect(() => {
    const sync = () => {
      normalizeLegacyHash();
      setRoute(routeFromPath());
      window.scrollTo({ top: 0, behavior: 'instant' });
    };
    window.addEventListener('popstate', sync);
    window.addEventListener('hashchange', sync); // in case a legacy #/ link is clicked

    // Intercept clicks on internal links so they do SPA nav instead of a reload.
    const onClick = (e) => {
      if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
      const a = e.target && e.target.closest && e.target.closest('a');
      if (!a) return;
      if (a.target === '_blank' || a.hasAttribute('download') || a.getAttribute('rel') === 'external') return;
      const href = a.getAttribute('href');
      if (!href || /^(mailto:|tel:|#)/.test(href)) return; // in-page anchors / mailto / tel
      let u;
      try { u = new URL(href, window.location.href); } catch (_) { return; }
      if (u.origin !== window.location.origin) return; // external
      e.preventDefault();
      window.navigate(u.pathname + u.search);
    };
    document.addEventListener('click', onClick);
    return () => {
      window.removeEventListener('popstate', sync);
      window.removeEventListener('hashchange', sync);
      document.removeEventListener('click', onClick);
    };
  }, []);
  return route;
};

const ContentContext = React.createContext(null);
const useContent = () => React.useContext(ContentContext) || {};

const useContentLoader = () => {
  const [content, setContent] = React.useState(null);
  React.useEffect(() => {
    let cancelled = false;
    fetch('/content.json', { cache: 'no-store' })
      .then(r => r.ok ? r.json() : {})
      .then(remote => {
        if (cancelled) return;
        let next = remote;
        try {
          const local = localStorage.getItem('aea_content_draft');
          if (local) next = JSON.parse(local);
        } catch (_) {}
        setContent(next);
      })
      .catch(() => setContent({}));
    return () => { cancelled = true; };
  }, []);
  return [content, setContent];
};

window.useContent = useContent;

// ─── Attribution capture: every page mount, persist URL + cookie params to sessionStorage,
//     and fire the Share Click beacon when ?ref= is present (once per ref per session).
const ATTRIBUTION_KEYS = [
  'utm_source','utm_medium','utm_campaign','utm_content','utm_term',
  'fbclid','gclid','ttclid','li_fat_id','msclkid','twclid','sccid',
  'ad_id','adset_id','campaign_id','placement','ref',
];
function readCookie(name) {
  if (typeof document === 'undefined') return null;
  const m = document.cookie.match(new RegExp('(^|; )' + name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '=([^;]*)'));
  return m ? decodeURIComponent(m[2]) : null;
}
function useAttributionCapture() {
  React.useEffect(() => {
    try {
      const url = new URL(window.location.href);
      const params = new URLSearchParams(url.search);
      // Hash params also matter for SPAs that put query after the #/route
      const hashIdx = window.location.hash.indexOf('?');
      const hashParams = hashIdx >= 0 ? new URLSearchParams(window.location.hash.slice(hashIdx + 1)) : null;

      const current = {};
      try { Object.assign(current, JSON.parse(sessionStorage.getItem('aea_attribution') || '{}')); } catch (_) {}

      for (const k of ATTRIBUTION_KEYS) {
        const v = params.get(k) || (hashParams && hashParams.get(k)) || null;
        if (v && !current[k]) current[k] = v;
      }
      const fbp = readCookie('_fbp');
      if (fbp && !current._fbp) current._fbp = fbp;
      if (!current.landing_url) current.landing_url = window.location.href;
      if (!current.landing_referrer) current.landing_referrer = document.referrer || null;
      if (!current.landing_at) current.landing_at = new Date().toISOString();
      sessionStorage.setItem('aea_attribution', JSON.stringify(current));

      // Share Click beacon — once per ref per session.
      if (current.ref) {
        const flagKey = `aea_ref_click_fired_${current.ref}`;
        if (!sessionStorage.getItem(flagKey)) {
          sessionStorage.setItem(flagKey, '1');
          fetch('/api/share-click', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              ref: current.ref,
              source_url: window.location.href,
              fbclid: current.fbclid || null,
            }),
            keepalive: true,
          }).catch(() => {});
        }
      }
    } catch (_) { /* never break the page on attribution issues */ }
  }, []);
}
window.useAttributionCapture = useAttributionCapture;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "primary": "#3DBDA8",
  "primaryDeep": "#1A6B5E",
  "accent": "#F5A623",
  "alert": "#D94040",
  "headlineMode": "hardship"
}/*EDITMODE-END*/;

const HEADLINES = {
  hardship: { main: "1 in 5 Australians can't afford", accent: "the power bill." },
  experiment: { main: "Australians are paying for an", accent: "energy experiment." },
  jobs: { main: "Power bills shouldn't cost you your", accent: "job, your home, your future." },
};

const App = () => {
  const route = useRoute();
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [content, setContent] = useContentLoader();
  useAttributionCapture();

  React.useEffect(() => {
    document.documentElement.style.setProperty('--teal', tweaks.primary);
    document.documentElement.style.setProperty('--teal-deep', tweaks.primaryDeep);
    document.documentElement.style.setProperty('--amber', tweaks.accent);
    document.documentElement.style.setProperty('--red', tweaks.alert);
  }, [tweaks]);

  React.useEffect(() => {
    const h = document.querySelector('.hero h1');
    if (!h) return;
    const choice = HEADLINES[tweaks.headlineMode] || HEADLINES.hardship;
    const main = (content && content.hero && content.hero.headlineMain) || choice.main;
    const accent = (content && content.hero && content.hero.headlineAccent) || choice.accent;
    h.innerHTML = `${main} <span class="accent">${accent}</span>`;
  }, [tweaks.headlineMode, route, content]);

  if (!content) return null;

  if (route === '/admin') {
    return (
      <ContentContext.Provider value={content}>
        <Admin content={content} setContent={setContent} />
      </ContentContext.Provider>
    );
  }

  let page;
  if (route.startsWith('/news/')) {
    const slug = decodeURIComponent(route.slice('/news/'.length));
    page = <NewsStory slug={slug} />;
  } else {
    switch (route) {
      case '/petition': page = <Petition />; break;
      case '/the-problem': page = <TheProblem />; break;
      case '/take-action': page = <TakeAction />; break;
      case '/news': page = <News />; break;
      case '/about-us': page = <About />; break;
      case '/privacy': page = <PrivacyPolicy />; break;
      case '/donate': page = <Donate />; break;
      case '/thank-you-petition': page = <ThankYouPetition />; break;
      case '/thank-you-donation': page = <ThankYouDonation />; break;
      case '/share': page = <SharePage />; break;
      default: page = <Home />;
    }
  }

  return (
    <ContentContext.Provider value={content}>
      <Header route={route} />
      {page}
      <Footer />
      {route !== '/donate' && <StickyMobileBar />}
      {route !== '/donate' && route !== '/share' && <SocialProofPopup route={route} />}
      <TweaksPanel title="Campaign Tweaks">
        <TweakSection title="Brand Colours">
          <TweakColor label="Primary teal" value={tweaks.primary} onChange={v => setTweak('primary', v)} options={['#3DBDA8','#2E86AB','#0F6E5F','#175C7C']} />
          <TweakColor label="Deep section bg" value={tweaks.primaryDeep} onChange={v => setTweak('primaryDeep', v)} options={['#1A6B5E','#0D1F1C','#1B3A52','#262626']} />
          <TweakColor label="Donate accent" value={tweaks.accent} onChange={v => setTweak('accent', v)} options={['#F5A623','#E85D2C','#C9A227','#F2C94C']} />
          <TweakColor label="Alert red" value={tweaks.alert} onChange={v => setTweak('alert', v)} options={['#D94040','#B22222','#E25822','#A22C29']} />
        </TweakSection>
        <TweakSection title="Hero Headline">
          <TweakRadio label="Message" value={tweaks.headlineMode} onChange={v => setTweak('headlineMode', v)} options={[
            {value: 'hardship', label: 'Hardship'},
            {value: 'experiment', label: 'Experiment'},
            {value: 'jobs', label: 'Jobs'},
          ]} />
        </TweakSection>
      </TweaksPanel>
    </ContentContext.Provider>
  );
};

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