/* calendar.jsx — Community Events Calendar (live data from /api/events) */

function parseTimeMinutes(t) {
  if (!t) return 9999;
  const m = t.match(/(\d+):(\d+)\s*(AM|PM)/i);
  if (!m) return 9999;
  let h = parseInt(m[1], 10);
  const min = parseInt(m[2], 10);
  const pm = m[3].toUpperCase() === 'PM';
  if (pm && h !== 12) h += 12;
  if (!pm && h === 12) h = 0;
  return h * 60 + min;
}

function sortEvents(evs) {
  return [...evs].sort((a, b) => {
    const dateDiff = (a.date || '').localeCompare(b.date || '');
    if (dateDiff !== 0) return dateDiff;
    return parseTimeMinutes(a.start) - parseTimeMinutes(b.start);
  });
}

// Colour for each stored category value (used for dots and active chip)
const CAT_COLORS = {
  'Festival':             '#c4612e',
  'Market':               '#cf9521',
  'Music':                '#9a3b4f',
  'Arts & Culture':       '#7b4fa0',
  'Sports & Recreation':  '#2a6496',
  'Family':               '#2f6f7e',
  'Community & Social':   '#5c7461',
  'Community':            '#5c7461', // legacy
  'Outdoors & Nature':    '#3f7d54',
  'Outdoors':             '#3f7d54', // legacy
  'Food & Drink':         '#c45e1a',
  'Indigenous & Cultural':'#a0522d',
  'Education':            '#2e6da4',
  'Gaming & Hobbies':     '#4a7c59',
  'Other':                '#7a5a8a',
};

// Filter chips — label is what the user sees, match is the list of stored category
// values that chip should include. Arts & Culture intentionally includes Music.
// Only chips with at least one matching event are rendered.
const CAT_FILTERS = [
  { label: 'All',                   match: null },
  { label: 'Arts & Culture',        match: ['Arts & Culture', 'Music'] },
  { label: 'Music',                 match: ['Music'] },
  { label: 'Sports & Recreation',   match: ['Sports & Recreation'] },
  { label: 'Family',                match: ['Family'] },
  { label: 'Community & Social',    match: ['Community & Social', 'Community'] },
  { label: 'Outdoors & Nature',     match: ['Outdoors & Nature', 'Outdoors'] },
  { label: 'Food & Drink',          match: ['Food & Drink'] },
  { label: 'Indigenous & Cultural', match: ['Indigenous & Cultural'] },
  { label: 'Education',             match: ['Education'] },
  { label: 'Gaming & Hobbies',      match: ['Gaming & Hobbies'] },
  { label: 'Market',                match: ['Market'] },
  { label: 'Festival',              match: ['Festival'] },
];

const RECURRENCE_LABEL = { Weekly:'Repeats weekly', 'Bi-weekly':'Repeats bi-weekly', Monthly:'Repeats monthly' };

// Hard-coded venue filters — add an entry here as each venue scraper goes live.
// Only shows as a chip if at least one event from that source is in the loaded data.
const VENUE_FILTERS = [
  { label: 'CN Centre',      source: 'CN Centre' },
  { label: 'Legion Hall',    source: 'Legion Hall' },
  { label: 'Trench Brewing', source: 'Trench Brewing' },
  { label: 'PG Library',     source: 'PG Library' },
  { label: 'Omineca Arts',       source: 'Omineca Arts' },
  { label: 'Exploration Place',  source: 'Exploration Place' },
  { label: 'Two Rivers Gallery', source: 'Two Rivers Gallery' },
  { label: 'Farmers Market',     source: 'PG Farmers Market' },
  { label: 'PGSO',              source: 'PGSO' },
  { label: 'Theatre NW',       source: 'Theatre NW' },
  { label: 'PG Playhouse',     source: 'PG Playhouse' },
  { label: 'Northern Lights Winery', source: 'Northern Lights Winery' },
  { label: 'Tourism PG',   source: 'Tourism PG' },
  { label: 'City of PG',   source: 'City of PG' },
  { label: 'Thirsty Moose', source: 'Thirsty Moose' },
  { label: 'Downtown PG',  source: 'Downtown PG' },
  { label: 'Wilson Square Market', source: 'Wilson Square Market' },
  { label: 'BCNE',                 source: 'BCNE' },
  { label: 'Caledonia Nordic',     source: 'Caledonia Nordic' },
  { label: 'Caledonia Ramblers',   source: 'Caledonia Ramblers' },
  { label: 'Knox Performance Centre', source: 'Knox Performance Centre' },
  { label: "Nancy O's",               source: "Nancy O's" },
  { label: 'Foodie Fridays',          source: 'Foodie Fridays' },
  { label: 'AHSPG',                   source: 'AHSPG' },
  { label: 'PG Golf & Curling',       source: 'PG Golf & Curling' },
  { label: 'PG Pride',                source: 'PG Pride' },
  { label: 'PGARA Speedway',          source: 'PGARA' },
  { label: 'Hart Pioneer Centre',     source: 'Hart Pioneer Centre' },
  { label: 'Youth Around Prince',     source: 'Youth Around Prince' },
];

/* Deduplicate recurring events — keep only the next upcoming occurrence per series */
function collapseRecurring(evList) {
  const seen = new Set();
  return evList.filter(e => {
    if (!e.recurring) return true;
    const key = (e.title + '|' + (e.venue || '')).toLowerCase();
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
}

function Calendar() {
  const { go } = useFF();
  const [events, setEvents]     = React.useState(null);
  const [cat,    setCat]        = React.useState('All');
  const [venue,  setVenue]      = React.useState(null); // null = all venues
  const [selDay, setSelDay]     = React.useState(null);
  const [showAll, setShowAll]   = React.useState(false);
  const [viewMonth, setViewMonth] = React.useState(() => {
    const now = new Date();
    return { year: now.getFullYear(), month: now.getMonth() };
  });

  React.useEffect(() => {
    fetch('/api/events')
      .then(r => r.ok ? r.json() : [])
      .then(data => setEvents(Array.isArray(data) ? data : []))
      .catch(() => setEvents([]));
  }, []);

  React.useEffect(() => {
    if (!events || events.length === 0) return;
    const ld = {
      '@context': 'https://schema.org',
      '@graph': events.slice(0, 20).map(e => ({
        '@type': 'Event',
        'name': e.title,
        'startDate': e.date,
        'location': {
          '@type': 'Place',
          'name': e.venue || 'Prince George, BC',
          'address': { '@type': 'PostalAddress', 'addressLocality': 'Prince George', 'addressRegion': 'BC', 'addressCountry': 'CA' }
        },
        'description': e.description || '',
        'url': e.link || 'https://fraserfinds.ca/#calendar',
        'organizer': { '@type': 'Organization', 'name': 'Fraser Finds', 'url': 'https://fraserfinds.ca' }
      }))
    };
    const existing = document.getElementById('ff-events-ld');
    const el = existing || document.createElement('script');
    el.id = 'ff-events-ld';
    el.type = 'application/ld+json';
    el.textContent = JSON.stringify(ld);
    if (!existing) document.head.appendChild(el);
  }, [events]);

  if (events === null) {
    return (
      <div>
        <PageBanner eyebrow="What's on" title="Events Calendar"
          sub="Markets, music, and community gatherings — the rhythm of a Prince George summer." />
        <div className="page-wrap" style={{ padding:'40px 28px', color:'var(--ink-faint)', fontFamily:'var(--serif)', fontStyle:'italic', fontSize:18 }}>
          Loading events…
        </div>
      </div>
    );
  }

  const activeCats = CAT_FILTERS.filter(f =>
    !f.match || events.some(e => f.match.includes(e.category))
  );
  const activeFilter = CAT_FILTERS.find(f => f.label === cat) || CAT_FILTERS[0];
  const activeVenues = VENUE_FILTERS.filter(v => events.some(e => e.source === v.source));
  const evAll = events
    .filter(e => !activeFilter.match || activeFilter.match.includes(e.category))
    .filter(e => !venue || e.source === venue);

  // calendar grid — all occurrences so dots are accurate
  const { year, month } = viewMonth;
  const first = new Date(year, month, 1).getDay();
  const dim   = new Date(year, month + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < first; i++) cells.push(null);
  for (let d = 1; d <= dim; d++) cells.push(d);
  while (cells.length % 7 !== 0) cells.push(null);

  const evByDay = {};
  evAll.forEach(e => {
    if (!e.date) return;
    const d = new Date(e.date + 'T12:00:00');
    if (isNaN(d.getTime())) return;
    if (d.getFullYear() !== year || d.getMonth() !== month) return;
    const day = d.getDate();
    (evByDay[day] = evByDay[day] || []).push(e);
  });

  // list — when a day is selected show everything on that day;
  // otherwise collapse recurring + apply 14-day window (unless showAll)
  let listEvents;
  if (selDay) {
    listEvents = sortEvents(evByDay[selDay] || []);
  } else {
    const collapsed = collapseRecurring(evAll);
    if (showAll) {
      listEvents = sortEvents(collapsed);
    } else {
      const cutoff = new Date();
      cutoff.setDate(cutoff.getDate() + 14);
      listEvents = sortEvents(collapsed.filter(e => {
        if (!e.date) return true;
        return new Date(e.date + 'T12:00:00') <= cutoff;
      }));
    }
  }

  const monthLabel = new Date(year, month, 1).toLocaleDateString('en-CA', { month:'long', year:'numeric' });
  const prevMonth = () => { setViewMonth(v => { const d = new Date(v.year, v.month-1,1); return {year:d.getFullYear(),month:d.getMonth()}; }); setSelDay(null); };
  const nextMonth = () => { setViewMonth(v => { const d = new Date(v.year, v.month+1,1); return {year:d.getFullYear(),month:d.getMonth()}; }); setSelDay(null); };

  // count how many events are beyond the 14-day window (for the "show more" label)
  const collapsed = collapseRecurring(evAll);
  const cutoff14  = new Date(); cutoff14.setDate(cutoff14.getDate() + 14);
  const hiddenCount = selDay ? 0 : collapsed.filter(e => e.date && new Date(e.date + 'T12:00:00') > cutoff14).length;

  return (
    <div>
      <PageBanner eyebrow="What's on" title="Events Calendar"
        sub="Markets, music, and community gatherings — the rhythm of a Prince George summer." />

      <window.SponsorStrip/>

      <div className="page-wrap" style={{ padding:'18px 28px 0', display:'flex', gap:8, flexWrap:'wrap' }}>
        {activeCats.map(f => (
          <button key={f.label} onClick={() => { setCat(f.label); setSelDay(null); setShowAll(false); }} className="chip"
            style={{ cursor:'pointer', fontSize:13.5, padding:'7px 14px',
              background: cat===f.label ? (CAT_COLORS[f.label]||'var(--spruce)') : 'var(--paper-3)',
              color: cat===f.label ? '#fff8ee' : 'var(--ink-soft)', borderColor:'transparent' }}>
            {f.label !== 'All' && <span style={{ width:8, height:8, borderRadius:'50%', background: cat===f.label ? '#fff8ee' : (CAT_COLORS[f.label]||'#888'), display:'inline-block', marginRight:5 }}/>}
            {f.label}
          </button>
        ))}
      </div>

      {activeVenues.length > 0 && (
        <div className="page-wrap" style={{ padding:'8px 28px 0', display:'flex', gap:8, flexWrap:'wrap', alignItems:'center' }}>
          <span style={{ fontSize:12, fontWeight:700, letterSpacing:'.06em', textTransform:'uppercase', color:'var(--ink-faint)', marginRight:2 }}>Venue/Source</span>
          {activeVenues.map(v => (
            <button key={v.source} onClick={() => { setVenue(venue === v.source ? null : v.source); setSelDay(null); setShowAll(false); }} className="chip"
              style={{ cursor:'pointer', fontSize:13, padding:'6px 13px',
                background: venue===v.source ? 'var(--spruce)' : 'var(--paper-3)',
                color: venue===v.source ? '#fff8ee' : 'var(--ink-soft)', borderColor:'transparent' }}>
              {v.label}
            </button>
          ))}
          {venue && <button onClick={() => setVenue(null)} style={{ background:'none', border:'none', color:'var(--ink-faint)', fontSize:12, cursor:'pointer', padding:'0 4px' }}>✕ clear</button>}
        </div>
      )}

      <div className="page-wrap cal-split" style={{ padding:'26px 28px 0', display:'grid', gridTemplateColumns:'1.3fr 1fr', gap:30, alignItems:'start' }}>
        {/* month grid */}
        <div className="card" style={{ padding:'22px 24px' }}>
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:16 }}>
            <button onClick={prevMonth} style={{ background:'none', border:'none', color:'var(--ink-soft)', padding:'4px 8px', borderRadius:8, cursor:'pointer' }}>‹</button>
            <h2 style={{ fontSize:24 }}>{monthLabel}</h2>
            <button onClick={nextMonth} style={{ background:'none', border:'none', color:'var(--ink-soft)', padding:'4px 8px', borderRadius:8, cursor:'pointer' }}>›</button>
          </div>
          {selDay && <button onClick={() => setSelDay(null)} style={{ display:'block', marginBottom:10, background:'none', border:'none', color:'var(--accent)', fontWeight:600, fontSize:14 }}>← Show all</button>}
          <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:6, fontSize:11.5, fontWeight:700, letterSpacing:'.08em', color:'var(--ink-faint)', textTransform:'uppercase', marginBottom:6 }}>
            {['Sun','Mon','Tue','Wed','Thu','Fri','Sat'].map(d => <div key={d} style={{ textAlign:'center' }}>{d}</div>)}
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'repeat(7,1fr)', gap:6 }}>
            {cells.map((d, i) => {
              const evs = d ? evByDay[d] : null;
              const has = evs && evs.length;
              const active = selDay === d;
              return (
                <button key={i} disabled={!d} onClick={() => has && setSelDay(active ? null : d)}
                  style={{ aspectRatio:'1', borderRadius:10, border:'1.5px solid '+(active?'var(--accent)':'transparent'),
                    background: d ? (active ? 'var(--accent)' : (has ? 'var(--paper-2)' : 'transparent')) : 'transparent',
                    cursor: has ? 'pointer' : 'default', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:4,
                    color: active ? '#fff8ee' : 'var(--ink)', position:'relative', padding:0 }}>
                  {d && <span style={{ fontWeight: has?700:500, fontSize:15 }}>{d}</span>}
                  {has && <span style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:2 }}>
                    <span style={{ display:'flex', gap:3 }}>
                      {evs.slice(0,3).map((e,j) => <span key={j} style={{ width:5, height:5, borderRadius:'50%',
                        background: active ? '#fff8ee' : (CAT_COLORS[e.category]||'var(--accent)') }}/>)}
                    </span>
                    {evs.length > 3 && <span style={{ fontSize:11, fontWeight:700, color: active ? '#fff8ee' : 'var(--accent)', lineHeight:1 }}>+{evs.length - 3}</span>}
                  </span>}
                </button>
              );
            })}
          </div>
          {events.length > 0 && (
            <div style={{ marginTop:18, paddingTop:16, borderTop:'1.5px solid var(--line)', display:'flex', gap:14, flexWrap:'wrap' }}>
              {CAT_FILTERS.filter(f => f.match && events.some(e => f.match.includes(e.category))).map(f => (
                <span key={f.label} style={{ display:'inline-flex', gap:6, alignItems:'center', fontSize:12.5, color:'var(--ink-soft)' }}>
                  <span style={{ width:8, height:8, borderRadius:'50%', background:CAT_COLORS[f.label]||'#888' }}/>{f.label}
                </span>
              ))}
            </div>
          )}
        </div>

        {/* list */}
        <div>
          <h3 style={{ fontSize:19, marginBottom:14 }}>
            {selDay ? `${monthLabel.split(' ')[0]} ${selDay}` : showAll ? 'All upcoming events' : 'Next 14 days'}
          </h3>
          <div style={{ display:'flex', flexDirection:'column', gap:12 }}>
            {listEvents.length === 0 && (
              <div style={{ color:'var(--ink-faint)', fontFamily:'var(--serif)', fontStyle:'italic', fontSize:16 }}>
                No events in the next 14 days — know of something happening? Add it below.
              </div>
            )}
            {listEvents.map((e, i) => (
              <div key={e.id || e.title + i} className="card" style={{ padding:'15px 17px', borderLeft:`4px solid ${CAT_COLORS[e.category]||'var(--accent)'}` }}>
                <div style={{ display:'flex', justifyContent:'space-between', gap:10, alignItems:'flex-start' }}>
                  <div style={{ fontFamily:'var(--display)', fontWeight:700, fontSize:17 }}>{e.title}</div>
                  {e.date && <span style={{ fontWeight:800, color:'var(--ink-faint)', fontSize:13, whiteSpace:'nowrap', flexShrink:0 }}>
                    {new Date(e.date + 'T12:00:00').toLocaleDateString('en-CA', { month:'short', day:'numeric' })}
                  </span>}
                </div>
                {e.recurring && (
                  <div style={{ fontSize:12, fontWeight:600, color:'var(--ink-faint)', marginTop:4, letterSpacing:'.04em' }}>
                    ↻ {RECURRENCE_LABEL[e.recurrence] || 'Recurring'}
                  </div>
                )}
                {e.description && <p style={{ color:'var(--ink-soft)', fontSize:14, margin:'6px 0 8px' }}>{e.description}</p>}
                <div style={{ display:'flex', gap:14, fontSize:13, color:'var(--ink-soft)', flexWrap:'wrap' }}>
                  {e.start && <span style={{ display:'inline-flex', gap:5, alignItems:'center' }}><IconClock size={14}/>{e.start}{e.end ? ` – ${e.end}` : ''}</span>}
                  {e.venue && <span style={{ display:'inline-flex', gap:5, alignItems:'center' }}><IconPin size={14}/>{e.venue}</span>}
                  {e.venue && <a href={`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(e.venue + ', Prince George, BC')}`} target="_blank" rel="noopener" onClick={() => window.ffTrack && window.ffTrack('directions', e.venue)} style={{ display:'inline-flex', gap:5, alignItems:'center', color:'var(--accent)' }}><IconRoute size={14}/>Directions</a>}
                  {e.link && <a href={e.link} target="_blank" rel="noopener" onClick={() => window.ffTrack && window.ffTrack('more_info', e.title)} style={{ display:'inline-flex', gap:5, alignItems:'center', color:'var(--river)' }}><IconGlobe size={14}/>More info</a>}
                </div>
                {e.photos && e.photos.length > 0 && <PhotoCarousel photos={e.photos} height={180} />}
              </div>
            ))}
          </div>

          {/* show more / show less */}
          {!selDay && (
            <div style={{ marginTop:14, display:'flex', gap:10, alignItems:'center' }}>
              {!showAll && hiddenCount > 0 && (
                <button onClick={() => setShowAll(true)} style={{ background:'none', border:'none', color:'var(--accent)', fontWeight:600, fontSize:14, cursor:'pointer', padding:0 }}>
                  Show {hiddenCount} more upcoming →
                </button>
              )}
              {showAll && (
                <button onClick={() => setShowAll(false)} style={{ background:'none', border:'none', color:'var(--ink-faint)', fontWeight:600, fontSize:14, cursor:'pointer', padding:0 }}>
                  ← Show less
                </button>
              )}
            </div>
          )}

          <button className="btn btn-dark" onClick={() => go('submit')} style={{ marginTop:16 }}><IconPlus size={16}/> Add an event</button>
        </div>
      </div>
      <div style={{ height:40 }}/>
    </div>
  );
}

window.Pages = window.Pages || {};
window.Pages.Calendar = Calendar;
