/* app.jsx — shell: header nav, footer, hash router, tweaks context */
const FFCtx = React.createContext(null);
const useFF = () => React.useContext(FFCtx);

const NAV = [
  { key:'home',       label:'Home' },
  { key:'calendar',   label:'Events' },
  { key:'foodtrucks', label:'Food Trucks' },
  { key:'farmstands', label:'Local Markets & Stands' },
  { key:'garage',     label:'Garage Sales', href:'/garagesales.html' },
  { key:'pulp',       label:'The Pulp', href:'/pulp' },
];

// Nav mark for The Pulp & Circumstance — mirrors the paper's own masthead
// (red block, blackletter P, hard ink shadow; palette from pulp.html)
function PulpMark({ size = 21 }) {
  return (
    <span style={{ width:size, height:size, flexShrink:0, background:'#b3261e', color:'#faf7f0',
      display:'grid', placeItems:'center', fontFamily:"'UnifrakturMaguntia', cursive",
      fontSize:size * 0.72, lineHeight:1, boxShadow:'2px 2px 0 #16130e' }}>P</span>
  );
}

const ACCENTS = {
  rust:   { accent:'#c4612e', deep:'#a44d22', soft:'#e2a273' },
  olive:  { accent:'#41431b', deep:'#2e3012', soft:'#aeb784' },
  river:  { accent:'#2f6f7e', deep:'#235460', soft:'#7eb0b8' },
  amber:  { accent:'#cf9521', deep:'#a9781a', soft:'#e8c879' },
};

function Logo({ onClick }) {
  return (
    <button onClick={onClick} style={{ display:'flex', alignItems:'center', gap:11, background:'none', border:'none', padding:0 }}>
      <span style={{ width:40, height:40, borderRadius:12, background:'var(--spruce)', display:'grid', placeItems:'center',
        boxShadow:'0 2px 0 var(--spruce-deep)' }}>
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--paper)" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round">
          <path d="M5 20c1-7 4-11 7-11M19 20c-1-5-3-8-5-9"/><path d="M12 9c0-3 2-5 2-5M12 4.5C12 3 10.5 2 9 2"/>
          <circle cx="12" cy="13.5" r="1.4" fill="var(--accent)" stroke="none"/>
        </svg>
      </span>
      <span style={{ fontFamily:'var(--display)', fontWeight:800, fontSize:22, letterSpacing:'-.02em', lineHeight:1 }}>
        Fraser<span style={{ color:'var(--accent)' }}>Finds</span>
        <span style={{ display:'block', fontFamily:'var(--body)', fontWeight:600, fontSize:10.5, letterSpacing:'.16em',
          textTransform:'uppercase', color:'var(--ink-faint)', marginTop:2 }}>Prince George, BC</span>
      </span>
    </button>
  );
}

function Header() {
  const { route, go } = useFF();
  const [open, setOpen] = React.useState(false);
  return (
    <header style={{ position:'sticky', top:0, zIndex:200, background:'rgba(248,243,225,.88)',
      backdropFilter:'blur(10px)', borderBottom:'1.5px solid var(--line)' }}>
      <div className="page-wrap" style={{ display:'flex', alignItems:'center', justifyContent:'space-between', height:74, gap:20 }}>
        <Logo onClick={()=>go('home')} />
        <nav className="ff-nav" style={{ display:'flex', alignItems:'center', gap:4 }}>
          {NAV.filter(n=>n.key!=='home').map(n=>{
            const active = route===n.key;
            if (n.key === 'pulp') {
              return (
                <a key={n.key} href={n.href} title="The Pulp & Circumstance"
                  style={{ display:'flex', alignItems:'center', gap:8, padding:'8px 13px', textDecoration:'none' }}>
                  <PulpMark/>
                  <span style={{ fontFamily:"Newsreader, Georgia, serif", fontStyle:'italic', fontWeight:500,
                    fontSize:15.5, color:'var(--ink-soft)' }}>The Pulp</span>
                </a>
              );
            }
            if (n.href) {
              return (
                <a key={n.key} href={n.href}
                  style={{ background:'none', border:'none', padding:'8px 13px', borderRadius:9, display:'block',
                    fontFamily:'var(--body)', fontWeight:600, fontSize:14.5, color:'var(--ink-soft)', textDecoration:'none' }}>
                  {n.label}
                </a>
              );
            }
            return (
              <button key={n.key} onClick={()=>go(n.key)}
                style={{ background: active?'var(--paper-3)':'none', border:'none', padding:'8px 13px', borderRadius:9,
                  fontFamily:'var(--body)', fontWeight:600, fontSize:14.5, color: active?'var(--ink)':'var(--ink-soft)' }}>
                {n.label}
              </button>
            );
          })}
        </nav>
        <div style={{ display:'flex', alignItems:'center', gap:10 }}>
          <button className="btn btn-primary ff-cta" onClick={()=>go('submit')}>
            <IconPlus size={17}/> <span>Add a listing</span>
          </button>
          <button className="ff-burger" onClick={()=>setOpen(o=>!o)} aria-label="Menu"
            style={{ display:'none', width:42, height:42, borderRadius:10, border:'1.5px solid var(--line)', background:'#fffdf6' }}>
            {open ? <IconClose size={20}/> : <IconMenu size={20}/>}
          </button>
        </div>
      </div>
      {open &&
        <div className="page-wrap" style={{ paddingBottom:14, display:'flex', flexWrap:'wrap', gap:8 }}>
          {NAV.filter(n=>n.key!=='home').map(n=>(
            n.key === 'pulp'
              ? <a key={n.key} href={n.href} className="chip"
                  style={{ fontSize:14, padding:'8px 14px', display:'inline-flex', alignItems:'center', gap:7 }}>
                  <PulpMark size={18}/>
                  <span style={{ fontFamily:'Newsreader, Georgia, serif', fontStyle:'italic', fontWeight:500 }}>The Pulp</span>
                </a>
              : n.href
              ? <a key={n.key} href={n.href} className="chip" style={{ fontSize:14, padding:'8px 14px' }}>{n.label}</a>
              : <button key={n.key} onClick={()=>{go(n.key);setOpen(false);}} className="chip"
                  style={{ fontSize:14, padding:'8px 14px' }}>{n.label}</button>
          ))}
        </div>}
    </header>
  );
}

function Footer() {
  const { go } = useFF();
  const isMobile = useIsMobile();
  return (
    <footer className="contour-bg" style={{ marginTop:80, color:'var(--paper)', padding:'52px 0 38px' }}>
      <div className="page-wrap" style={{ display:'grid', gridTemplateColumns: isMobile ? '1fr' : '1.4fr 1fr 1fr', gap: isMobile ? 32 : 36 }}>
        <div>
          <div style={{ fontFamily:'var(--display)', fontWeight:800, fontSize:24 }}>Fraser<span style={{color:'var(--accent-soft)'}}>Finds</span>.ca</div>
          <p style={{ color:'rgba(248,243,225,.72)', maxWidth:320, marginTop:10, fontSize:15 }}>
            A neighbourly guide to Prince George — made by locals, for locals. Got something to add? We'd love to hear it.
          </p>
          <button className="btn" onClick={()=>go('submit')} style={{ marginTop:8, background:'var(--accent)', color:'#fff8ee' }}>
            <IconPlus size={16}/> Add a listing
          </button>
        </div>
        <div>
          <div style={{ fontFamily:'var(--body)', fontWeight:700, fontSize:12, letterSpacing:'.16em', textTransform:'uppercase', color:'var(--accent-soft)', marginBottom:12 }}>Explore</div>
          {NAV.map(n=>(
            <div key={n.key} style={{ marginBottom:8 }}>
              {n.href
                ? <a href={n.href} style={{ color:'rgba(248,243,225,.82)', fontSize:15 }}>{n.label}</a>
                : <button onClick={()=>go(n.key)} style={{ background:'none', border:'none', color:'rgba(248,243,225,.82)', padding:0, fontSize:15 }}>{n.label}</button>}
            </div>
          ))}
        </div>
        <div>
          <div style={{ fontFamily:'var(--body)', fontWeight:700, fontSize:12, letterSpacing:'.16em', textTransform:'uppercase', color:'var(--accent-soft)', marginBottom:12 }}>The fine print</div>
          <p style={{ color:'rgba(248,243,225,.62)', fontSize:13.5, lineHeight:1.6 }}>
            A community project, not an official City of Prince George service. Listings are submitted by residents and may not be verified.
            © 2026 FraserFinds.ca
          </p>
          <a href="mailto:admin@fraserfinds.ca"
            style={{ display:'inline-block', marginTop:10, color:'rgba(248,243,225,.72)', fontSize:13.5, textDecoration:'none',
              borderBottom:'1px solid rgba(248,243,225,.3)' }}>
            admin@fraserfinds.ca
          </a>
        </div>
      </div>
    </footer>
  );
}

/* ---- Sponsor strip ---- */
function SponsorStrip() {
  const [sponsors, setSponsors] = React.useState([]);
  const [idx, setIdx] = React.useState(0);
  const isMobile = useIsMobile();

  React.useEffect(() => {
    fetch('/sponsors/sponsors.txt')
      .then(r => r.text())
      .then(txt => {
        const list = txt.split('\n')
          .map(l => l.trim())
          .filter(l => l && !l.startsWith('#'))
          .map(l => {
            const [logo, banner, name, url] = l.split('|').map(s => s.trim());
            return { logo: `/sponsors/${logo}`, banner: `/sponsors/${banner}`, name, url };
          })
          .filter(s => s.name && s.url);
        const daySlot = Math.floor(Date.now() / 86400000) % list.length;
        setIdx(daySlot);
        setSponsors(list);
      })
      .catch(() => {});
  }, []);

  React.useEffect(() => {
    if (sponsors.length < 2) return;
    const t = setInterval(() => setIdx(i => (i + 1) % sponsors.length), 30000);
    return () => clearInterval(t);
  }, [sponsors.length]);

  if (sponsors.length === 0) return null;
  const s = sponsors[idx];

  return (
    <div style={{ borderBottom:'1.5px solid var(--line)', background:'var(--paper-2)', padding:'10px 0 14px' }}>
      <div style={{ fontSize:11, fontWeight:700, letterSpacing:'.14em', textTransform:'uppercase', color:'var(--ink-faint)', textAlign:'center', marginBottom:8 }}>Brought to you by</div>
      <a href={s.url} target="_blank" rel="noopener" title={s.name}
        onClick={() => { if (window.ffTrack) window.ffTrack('ad_click', s.name); }}
        style={{ display:'block', textAlign:'center' }}>
        <img src={isMobile ? s.logo : s.banner} alt={s.name} style={{ display:'block', width:'100%', height:'auto', maxHeight: isMobile ? undefined : 120, objectFit: isMobile ? undefined : 'contain', opacity:.95 }}/>
      </a>
    </div>
  );
}

/* ---- Pulp nudge ---- */
// PulpNudge — a gentle "EXTRA! EXTRA!" toast that floats up from the corner
// after ~15 s on the site with the Pulp's current top headline. Mounted in the
// App shell (NOT inside <main class="rise">: its retained animation transform
// would hijack position:fixed and pin the toast to the page bottom instead of
// the viewport) so the timer keeps running while visitors click between
// sections. Frequency-capped per browser (localStorage ff_pulp_nudge): it
// returns only for a fresh top headline (3-day minimum between showings) or
// after 3 quiet weeks.
function PulpNudge() {
  const [art, setArt] = React.useState(null);
  const [out, setOut] = React.useState(false);

  React.useEffect(() => {
    const KEY = 'ff_pulp_nudge';
    let stored = null;
    try { stored = JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (_) {}
    let timer, dead = false;
    fetch('/api/pulp/articles')
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        const top = data && data.articles && data.articles[0];
        if (!top || !top.hed || dead) return; // no headline, no nudge
        const days = stored ? (Date.now() - (stored.t || 0)) / 864e5 : Infinity;
        const due = !stored || (days >= 3 && stored.h !== top.hed) || days >= 21;
        if (!due) return;
        timer = setTimeout(() => {
          if (dead) return;
          setArt(top);
          try { localStorage.setItem(KEY, JSON.stringify({ h: top.hed, t: Date.now() })); } catch (_) {}
          if (window.ffTrack) window.ffTrack('pulp_nudge', 'shown');
        }, 15000);
      })
      .catch(() => {});
    return () => { dead = true; clearTimeout(timer); };
  }, []);

  if (!art) return null;

  const dismiss = () => {
    if (window.ffTrack) window.ffTrack('pulp_nudge', 'dismiss');
    setOut(true);
    setTimeout(() => setArt(null), 400);
  };

  return (
    <div style={{ position:'fixed', right:18, bottom:18, zIndex:80,
        width:'min(340px, calc(100vw - 36px))',
        animation: out ? 'ffNudgeOut .38s ease forwards' : 'ffNudgeIn .55s cubic-bezier(.2,.9,.3,1.12)' }}>
      <style>{`
        @keyframes ffNudgeIn  { from { transform: translateY(130%) rotate(3deg); opacity: 0 } to { transform: none; opacity: 1 } }
        @keyframes ffNudgeOut { to { transform: translateY(140%) rotate(4deg); opacity: 0 } }
      `}</style>
      <div style={{ background:'#f7f2e4', border:'2px solid var(--ink)', borderRadius:4,
          boxShadow:'0 14px 34px rgba(44,37,25,.35)', padding:'14px 16px 13px',
          transform:'rotate(-.6deg)', position:'relative' }}>
        <button onClick={dismiss} aria-label="No thanks" style={{ position:'absolute', top:5, right:9,
            border:'none', background:'none', fontSize:20, lineHeight:1, cursor:'pointer',
            color:'var(--ink-soft)', padding:2 }}>×</button>
        <div style={{ fontSize:11, fontWeight:800, letterSpacing:'.2em', color:'#9a3b4f', paddingRight:18 }}>
          EXTRA! EXTRA! ✦ THE PULP &amp; CIRCUMSTANCE
        </div>
        <div style={{ fontFamily:'var(--serif)', fontWeight:900, fontSize:18.5, lineHeight:1.25, margin:'8px 0 9px' }}>
          “{art.hed}”
        </div>
        <a href="/pulp" onClick={() => { if (window.ffTrack) window.ffTrack('pulp_nudge', 'click'); }}
           style={{ display:'inline-flex', alignItems:'center', gap:5, color:'#9a3b4f',
                    fontWeight:700, fontSize:13.5, textDecoration:'none' }}>
          Read the story <IconArrow size={14}/>
        </a>
      </div>
    </div>
  );
}

/* ---- Tweaks ---- */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "rust",
  "homeLayout": "almanac",
  "mapStyle": "illustrated"
}/*EDITMODE-END*/;

function FFTweaks() {
  const { t, setTweak } = useFF();
  return (
    <TweaksPanel>
      <TweakSection label="Theme" />
      <TweakColor label="Accent colour" value={ACCENTS[t.accent]?.accent}
        options={[ACCENTS.rust.accent, ACCENTS.olive.accent, ACCENTS.river.accent, ACCENTS.amber.accent]}
        onChange={(v)=>{ const k = Object.keys(ACCENTS).find(k=>ACCENTS[k].accent===v); setTweak('accent', k||'rust'); }} />
      <TweakSection label="Home page" />
      <TweakRadio label="Layout" value={t.homeLayout} options={['almanac','hero']}
        onChange={(v)=>setTweak('homeLayout', v)} />
    </TweaksPanel>
  );
}

/* ---- Router ---- */
const ROUTES = {
  home:       () => <window.Pages.Home/>,
  calendar:   () => <window.Pages.Calendar/>,
  foodtrucks: () => <window.Pages.FoodTrucks/>,
  farmstands: () => <window.Pages.FarmStands/>,
  submit:     () => <window.Pages.Submit/>,
};

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [route, setRoute] = React.useState(() => (location.hash.replace('#','') || 'home'));

  React.useEffect(() => {
    const h = () => setRoute(location.hash.replace('#','') || 'home');
    window.addEventListener('hashchange', h);
    return () => window.removeEventListener('hashchange', h);
  }, []);

  const go = (r) => {
    location.hash = r;
    window.scrollTo({ top:0, behavior: 'instant' in window ? 'instant' : 'auto' });
    if (window.ffTrack) window.ffTrack('page_load', r);
  };

  React.useEffect(() => {
    if (window.ffTrack) window.ffTrack('pageview', route);
  }, []);

  React.useEffect(() => {
    const a = ACCENTS[t.accent] || ACCENTS.rust;
    const root = document.documentElement;
    root.style.setProperty('--accent', a.accent);
    root.style.setProperty('--accent-deep', a.deep);
    root.style.setProperty('--accent-soft', a.soft);
  }, [t.accent]);

  const accent = (ACCENTS[t.accent] || ACCENTS.rust).accent;
  const ctx = { t, setTweak, route, go, accent };
  const View = ROUTES[route] || ROUTES.home;

  return (
    <FFCtx.Provider value={ctx}>
      <div className="ff-map-bg" style={{ opacity: 0.07 }}><MapArt /></div>
      <Header/>
      <main key={route} className="rise"><View/></main>
      <Footer/>
      <PulpNudge/>
      <FFTweaks/>
    </FFCtx.Provider>
  );
}

function useIsMobile(breakpoint) {
  var bp = breakpoint || 768;
  const [mobile, setMobile] = React.useState(() => window.innerWidth <= bp);
  React.useEffect(() => {
    const mq = window.matchMedia('(max-width: ' + bp + 'px)');
    const h = e => setMobile(e.matches);
    mq.addEventListener('change', h);
    return () => mq.removeEventListener('change', h);
  }, [bp]);
  return mobile;
}

Object.assign(window, { FFCtx, useFF, ACCENTS, useIsMobile, SponsorStrip });
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
