/* global React */
const { useState, useEffect } = React;

/* Shared lightbox — used by any page that shows images the user can zoom.
   Returns an `open` function to trigger, and `LightboxPortal` to render.
   Bind `open({ src, cap })` to any element's onClick. Clicking the backdrop,
   the × button, or pressing Escape closes. Body scroll is locked while open.

   The modal is rendered through ReactDOM.createPortal into document.body so
   that `position: fixed` on .lightbox resolves against the viewport. Without
   the portal, ancestors with `transform` or `filter` (e.g. the .site-in
   wrapper's fade-up animation) become the containing block for fixed
   descendants and the modal ends up pinned to the top of the site content
   instead of centred on screen. */
function useLightbox() {
  const [lightbox, setLightbox] = useState(null);
  useEffect(() => {
    if (!lightbox) return;
    const onKey = (e) => { if (e.key === 'Escape') setLightbox(null); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.style.overflow = '';
    };
  }, [lightbox]);
  const open = (item) => setLightbox(item);
  const close = () => setLightbox(null);
  const LightboxPortal = lightbox ? ReactDOM.createPortal(
    <div className="lightbox" onClick={close}>
      <button className="lightbox-close" onClick={close}>×</button>
      <img src={lightbox.src} alt={lightbox.cap || ''} onClick={(e) => e.stopPropagation()} />
      {lightbox.cap && <div className="lightbox-caption">{lightbox.cap}</div>}
    </div>,
    document.body
  ) : null;
  return { open, close, LightboxPortal };
}

/* ============ ABOUT ============ */
function AboutPage() {
  const paras = [
    "I am 22, a Manchester City supporter for as long as I can remember, and genuinely obsessed with how the game is played. What interests me most is the shape of teams, the decisions players make, and the patterns that emerge when you watch matches closely. The numbers came later. Now I sit somewhere between the two, watching first and then going to the data to see whether what I noticed was really there.",
    "My footballing background starts on the playing side. Before university I came through the Middlesex FA U16s and played for Rayners Lane U18s at semi-pro level, before taking a step back to focus on my studies. Football never really went anywhere, though. I played for two of my three years at the Oxford university club and competed in two Varsity matches, winning both.",
    "I read Politics, Philosophy and Economics at the University of Oxford. Within the economics branch, it was the econometrics and quantitative economics modules in particular that pulled me into data analysis as a whole, and my love for football was what tied the two together.",
    "A year after graduating I came back to the club to coach the Oxford Men's 2nd Team through the 2025/26 season, keeping them in BUCS Midlands Tier 3 in their first year after promotion. Alongside the coaching I spent the year on a sabbatical supporting OUAFC, the main university football club, and running OUCFA, the Oxford college football leagues.",
    "What I want next is to hone my skills and apply them across different footballing contexts. Coaching, performance analysis, scouting, video, opposition analysis: each one demands its own specific skill set, and I am eager to develop in any of them.",
  ];
  const facts = [
    ['Currently', 'Open to opportunities across football. Coaching, performance analysis, scouting.'],
    ['Studied', 'Politics, Philosophy & Economics at Oxford. Econometrics and quantitative economics within the economics branch.'],
    ['Playing', 'Middlesex FA U16s. Rayners Lane U18s (semi-pro). Two wins from two Oxford Varsity matches.'],
    ['Coaching', "Head coach, Oxford Men's 2nd Team, 2025/26. Sabbatical supporting OUAFC and running OUCFA."],
    ['Inspirations', 'Pep Guardiola and Luis Enrique. Positional play and exceptional pressing football.'],
    ['Based', 'United Kingdom. Open to relocating for the right opportunity.'],
  ];
  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <span className="eyebrow">About</span>
          <h1>Manchester City supporter, data analyst, coach.</h1>
          <p className="section-lead">Who I am, what I do, and the kind of role I want next inside the game.</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner">
          <div className="about-grid">
            <div className="about-text">
              {paras.map((p, i) => <p key={i} className="reveal" style={{ '--d': `${i * 80}ms` }}>{p}</p>)}
            </div>
            <div className="about-facts">
              {facts.map(([l, v], i) => (
                <div className="fact reveal" key={l} style={{ '--d': `${i * 60}ms` }}>
                  <div className="fact-label">{l}</div>
                  <div className="fact-value">{v}</div>
                </div>
              ))}
            </div>
          </div>
          <div className="page-footer-cta">
            <a className="btn btn-primary" onClick={(e) => { e.preventDefault(); window.navigate('philosophy'); }}>Next: Football philosophy →</a>
            <a className="btn btn-secondary" onClick={(e) => { e.preventDefault(); window.navigate('home'); }}>← Back to home</a>
          </div>
        </div>
      </section>
    </>
  );
}

/* ============ PHILOSOPHY ============ */
function PhilosophyPage() {
  const influences = [
    { name: 'Pep Guardiola', role: 'Positional play · Controlled dominance',
      text: "Positional play (juego de posición), inverted fullbacks, centre-backs stepping into midfield, the free man as a design output rather than an accident. Guardiola's teams are built to guarantee that someone is always unmarked somewhere, and the system is organised so the pass to that player is always on." },
    { name: 'Luis Enrique', role: 'High press · Positionless future',
      text: "Enrique is the coach whose current work I find most exciting. His PSG side is slowly but surely transitioning into a form of 'positionless' football, a system where every player is expected to read space, rotate through midfield, carry the ball, defend the high line, and finish a chance if one falls their way. This is the direction the next decade of elite football is moving in." },
  ];
  const principles = [
    ['Positional play', 'The pitch broken into zones, players occupying specific positions relative to each other to guarantee numerical and positional superiority in every phase.'],
    ['Possession with purpose', 'Patience that probes, draws pressure, and then breaks lines through decisive passes. Not recycling at the back without intent.'],
    ['The high press as the first phase of attack', 'Winning the ball back where you can hurt the opposition, through organised pressing traps rather than individual chasing.'],
    ['Immediate defensive transitions', 'Everyone behind the ball the instant you lose it. The ability to transition well is what lets a team press high and attack boldly without being exposed.'],
    ['Half-space domination', 'The channels between the fullback and centre-back are the most dangerous zones on the pitch. Teams that occupy them consistently make defences make decisions they cannot win.'],
    ['Ball-playing defenders', 'Centre-backs who can carry the ball, step into midfield, and break lines with passes or runs.'],
    ['Width as a tool', 'Wide players who genuinely stretch the defence and attack the shoulder of a fullback, so attackers inside have room to operate.'],
    ['Structure over aggression', 'Elegant defensive organisation, positional discipline, compact lines, every passing angle cut.'],
  ];
  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <span className="eyebrow">Football Philosophy</span>
          <h1>Proactive football. Structure on the ball. Pressure off it.</h1>
          <p className="section-lead">The football I find most interesting, shaped most directly by Pep Guardiola and Luis Enrique.</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner">
          <div className="influences">
            {influences.map((inf, i) => (
              <div className="influence reveal" key={inf.name} style={{ '--d': `${i * 100}ms` }}>
                <div className="influence-name">{inf.name}</div>
                <div className="influence-role">{inf.role}</div>
                <p>{inf.text}</p>
              </div>
            ))}
          </div>

          <h2 className="section-h2" style={{ marginTop: '4rem', marginBottom: '0.8rem' }}>The principles I look for.</h2>
          <p className="section-lead">When I watch a team, these are the patterns that tell me how the head coach thinks.</p>

          <div className="principles-grid">
            {principles.map(([h, p], i) => (
              <div className="principle reveal" key={h} style={{ '--d': `${i * 60}ms` }}>
                <h3>{h}</h3>
                <p>{p}</p>
              </div>
            ))}
          </div>

          <div className="page-footer-cta">
            <a className="btn btn-primary" onClick={(e) => { e.preventDefault(); window.navigate('analysis'); }}>Next: Written pieces →</a>
            <a className="btn btn-secondary" onClick={(e) => { e.preventDefault(); window.navigate('about'); }}>← Back to About</a>
          </div>
        </div>
      </section>
    </>
  );
}

/* ============ ANALYSIS ============ */
/* Piece content lives in website/pieces/{id}.md and is fetched at runtime.
   Edit the markdown file, commit, push — Cloudflare redeploys and the site
   picks up the new content automatically. Each file has frontmatter
   (id, title, meta, heroImage, lede) and a markdown body where a single
   `#` starts a top-level section, `##` a subheading, and `![cap](src)` a
   figure. Paragraphs are separated by blank lines. */

function parsePiece(text) {
  const fmMatch = text.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
  if (!fmMatch) return null;
  const fm = {};
  fmMatch[1].split('\n').forEach(line => {
    const m = line.match(/^(\w+):\s*(.*)$/);
    if (m) fm[m[1]] = m[2].trim();
  });
  const body = fmMatch[2];
  const sections = [];
  let current = null;
  const lines = body.split('\n');
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    if (line.startsWith('# ')) {
      if (current) sections.push(current);
      current = { h: line.slice(2).trim(), blocks: [] };
      continue;
    }
    if (!current) continue;
    if (line.startsWith('## ')) {
      current.blocks.push({ t: 'h3', x: line.slice(3).trim() });
      continue;
    }
    const imgMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)\s*$/);
    if (imgMatch) {
      current.blocks.push({ t: 'fig', cap: imgMatch[1], src: imgMatch[2] });
      continue;
    }
    if (line.trim()) {
      const paraLines = [line];
      while (i + 1 < lines.length && lines[i+1].trim() && !lines[i+1].startsWith('#') && !lines[i+1].startsWith('![')) {
        i++;
        paraLines.push(lines[i]);
      }
      current.blocks.push({ t: 'p', x: paraLines.join(' ').trim() });
    }
  }
  if (current) sections.push(current);
  return { ...fm, sections };
}

function fetchPieces() {
  return Promise.all([
    fetch('./pieces/city.md').then(r => r.text()),
    fetch('./pieces/stones.md').then(r => r.text()),
  ]).then(([cityText, stonesText]) => ({
    city: parsePiece(cityText),
    stones: parsePiece(stonesText),
  }));
}

function AnalysisListPage({ onPick, pieces }) {
  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <span className="eyebrow">Analysis</span>
          <h1>Full written pieces, match by match.</h1>
          <p className="section-lead">Each piece is a self-contained analysis: a clear tactical argument, supported by data visualisations, written for readers who watch a lot of football and are starting to read analytics too.</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner">
          <div className="pieces-grid">
            {[pieces.city, pieces.stones].map((p, i) => (
              <a key={p.id} className="piece-card reveal" style={{ '--d': `${i * 120}ms` }} href="#" onClick={(e)=>{e.preventDefault();onPick(p.id);}}>
                <div className="piece-card-image"><img src={p.heroImage} alt="" /></div>
                <div className="piece-card-content">
                  <div className="piece-card-meta">{p.meta.split(' · ').map((m, j) => <span key={j}>{m}</span>)}</div>
                  <h3>{p.title}</h3>
                  <p>{p.lede}</p>
                  <span className="piece-card-cta">Read the full piece →</span>
                </div>
              </a>
            ))}
          </div>
          <div className="page-footer-cta">
            <a className="btn btn-primary" onClick={(e) => { e.preventDefault(); window.navigate('visuals'); }}>Next: Visual work →</a>
            <a className="btn btn-secondary" onClick={(e) => { e.preventDefault(); window.navigate('philosophy'); }}>← Back to Philosophy</a>
          </div>
        </div>
      </section>
    </>
  );
}

function AnalysisPiece({ piece, onBack, onPickOther, other }) {
  const { open, LightboxPortal } = useLightbox();
  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <a href="#" className="breadcrumb" onClick={(e)=>{e.preventDefault();onBack();}}>← All analysis</a>
          <span className="eyebrow">{piece.meta}</span>
          <h1>{piece.title}</h1>
          <p className="section-lead">{piece.lede}</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner article">
          {piece.sections.map((s, i) => (
            <div key={i} className="article-section reveal" style={{ '--d': `${i * 40}ms` }}>
              <h2 className="article-h2">{s.h}</h2>
              {s.blocks.map((b, j) => {
                if (b.t === 'h3')  return <h3 key={j} className="article-h3">{b.x}</h3>;
                if (b.t === 'p')   return <p  key={j} className="article-p">{b.x}</p>;
                if (b.t === 'fig') return (
                  <figure key={j} className="article-figure" onClick={() => open({ src: b.src, cap: b.cap })}>
                    <img src={b.src} alt={b.cap || ''} />
                    {b.cap && <figcaption className="article-caption">{b.cap}</figcaption>}
                  </figure>
                );
                return null;
              })}
            </div>
          ))}
          <div className="page-footer-cta">
            <a className="btn btn-primary" onClick={(e)=>{e.preventDefault();onPickOther();}}>Read: {other.title.split(' · ')[0]} →</a>
            <a className="btn btn-secondary" onClick={(e)=>{e.preventDefault();onBack();}}>← All analysis</a>
          </div>
        </div>
      </section>
      {LightboxPortal}
    </>
  );
}

function AnalysisPage({ payload }) {
  const [selected, setSelected] = useState(payload && payload.piece ? payload.piece : null);
  const [pieces, setPieces] = useState(null);
  const [loadError, setLoadError] = useState(false);

  useEffect(() => {
    fetchPieces().then(setPieces).catch(err => {
      console.error('Failed to load pieces:', err);
      setLoadError(true);
    });
  }, []);

  useEffect(() => {
    const h = (e) => {
      if (e.detail && e.detail.page === 'analysis' && e.detail.payload && e.detail.payload.piece) {
        setSelected(e.detail.payload.piece);
        window.scrollTo({ top: 0, behavior: 'smooth' });
      } else if (e.detail && e.detail.page === 'analysis' && e.detail.payload && !e.detail.payload.piece) {
        setSelected(null);
      }
    };
    window.addEventListener('jcg:nav', h);
    return () => window.removeEventListener('jcg:nav', h);
  }, []);

  if (loadError) return (
    <section className="page-hero"><div className="page-hero-inner">
      <h1>Could not load pieces.</h1>
      <p className="section-lead">Please refresh the page. If the problem persists, the markdown files may be missing.</p>
    </div></section>
  );
  if (!pieces) return (
    <section className="page-hero"><div className="page-hero-inner">
      <p className="section-lead">Loading…</p>
    </div></section>
  );
  if (!selected) return <AnalysisListPage onPick={setSelected} pieces={pieces} />;
  const piece = pieces[selected];
  const other = pieces[selected === 'city' ? 'stones' : 'city'];
  return <AnalysisPiece piece={piece} other={other} onBack={()=>setSelected(null)} onPickOther={()=>{setSelected(other.id); window.scrollTo({top:0,behavior:'auto'});}} />;
}

/* ============ VISUALS ============ */
const CITY_VISUALS = [
  ['02_arsenal_buildup_suffocation', 'Arsenal build-up suffocation'],
  ['03_aerial_dominance', 'Aerial dominance'],
  ['05_avg_positions_both', 'Average positions · both teams'],
  ['06_cherki_heatmap', 'Cherki heatmap'],
  ['07_semenyo_heatmap', 'Semenyo heatmap'],
  ['08_cherki_vs_semenyo', 'Cherki vs Semenyo'],
  ['10_xt_zones', 'Cherki & Semenyo · xT zones'],
  ['11_oreilly_heatmap', "O'Reilly heatmap"],
  ['15_nunes_heatmap', 'Nunes heatmap'],
  ['20_momentum', 'Match momentum'],
  ['21_ball_progression', 'Ball progression'],
  ['22_carry_vs_progression', 'Carry vs progression'],
  ['23_oreilly_radar', "O'Reilly radar"],
  ['24_cherki_radar', 'Cherki radar'],
];
const STONES_VISUALS = [
  ['01_stones_heatmap', 'Stones heatmap'],
  ['02_comparative_heatmaps', 'Comparative heatmaps'],
  ['03_average_positions_both_teams', 'Average positions · both teams'],
  ['04_stones_xt_zones', 'Stones · xT zones'],
  ['05_stones_passing_zones', 'Stones passing zones'],
  ['06_stones_duels', 'Stones duels'],
  ['07c_annotated_shot_map', 'Annotated shot map'],
  ['10_stones_ball_progression', 'Stones ball progression'],
];

function VisualsPage() {
  const [filter, setFilter] = useState('all');
  const { open, LightboxPortal } = useLightbox();

  const city = CITY_VISUALS.map(([f, c]) => ({ src: `./assets/visuals/city/${f}.png`, cap: c, match: 'city' }));
  const stones = STONES_VISUALS.map(([f, c]) => ({ src: `./assets/visuals/stones/${f}.png`, cap: c, match: 'stones' }));
  const total = city.length + stones.length;

  const show = (match) => filter === 'all' || filter === match;

  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <span className="eyebrow">Visual Work</span>
          <h1>The full library · {total} visuals.</h1>
          <p className="section-lead">Every chart from both matches, built in Python using matplotlib and mplsoccer. Click any visual to open full size.</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner">
          <div className="piece-tabs" role="tablist">
            <button className={'piece-tab ' + (filter === 'all' ? 'is-active' : '')} onClick={() => setFilter('all')}>All ({total})</button>
            <button className={'piece-tab ' + (filter === 'city' ? 'is-active' : '')} onClick={() => setFilter('city')}>Arsenal 0–2 City ({city.length})</button>
            <button className={'piece-tab ' + (filter === 'stones' ? 'is-active' : '')} onClick={() => setFilter('stones')}>Stones · CL Final ({stones.length})</button>
          </div>

          {show('city') && (
            <div>
              <div className="library-section-header">
                <h2>Arsenal 0–2 Manchester City · EFL Cup Final</h2>
                <span className="meta">22 March 2026 · {city.length} visuals</span>
              </div>
              <div className="gallery">
                {city.map((v, i) => (
                  <div className="gallery-item reveal" key={v.src} style={{ '--d': `${i * 25}ms` }} onClick={()=>open(v)}>
                    <img src={v.src} alt={v.cap} loading="lazy" />
                    <div className="gallery-caption">{v.cap}</div>
                  </div>
                ))}
              </div>
            </div>
          )}

          {show('stones') && (
            <div>
              <div className="library-section-header">
                <h2>John Stones · Champions League Final · Inter vs Manchester City</h2>
                <span className="meta">10 June 2023 · {stones.length} visuals</span>
              </div>
              <div className="gallery">
                {stones.map((v, i) => (
                  <div className="gallery-item reveal" key={v.src} style={{ '--d': `${i * 25}ms` }} onClick={()=>open(v)}>
                    <img src={v.src} alt={v.cap} loading="lazy" />
                    <div className="gallery-caption">{v.cap}</div>
                  </div>
                ))}
              </div>
            </div>
          )}

          <div className="page-footer-cta">
            <a className="btn btn-primary" onClick={(e) => { e.preventDefault(); window.navigate('data'); }}>Next: Data methodology →</a>
            <a className="btn btn-secondary" onClick={(e) => { e.preventDefault(); window.navigate('analysis'); }}>← Back to Analysis</a>
          </div>
        </div>
      </section>

      {LightboxPortal}
    </>
  );
}

/* ============ DATA ============ */
function DataPage() {
  const sources = [
    ['SofaScore', 'match-level event data', 'Touch heatmaps, shot coordinates, player ratings, momentum timelines, average positions. My primary source for current-season match analysis and for matches where StatsBomb open data does not reach.'],
    ['FBref', 'season and player aggregates', 'Advanced season metrics: progressive passes, progressive carries, xG, xAG, touches by zone. The foundation for player radar profiles and cross-season comparisons. Data sourced from StatsBomb.'],
    ['StatsBomb Open Data', 'full event-level coordinates', 'Passes, carries and shots with full start and end coordinates for selected competitions. The gold standard for pitch visualisations where coverage exists.'],
    ['Understat', 'xG shot data', 'Shot-level xG values and coordinates across the major European leagues going back several seasons.'],
    ['Transfermarkt', 'squad context', 'Squad lists, player ages, transfer histories, market values. Background context rather than analysis.'],
    ['Manual match coding', 'closing the gaps', 'Where free data does not cover a specific sequence or event, I code it from video manually. Slower, but the only way to build some of the visuals that matter.'],
  ];
  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <span className="eyebrow">Data Methodology</span>
          <h1>All sourced from free, publicly available platforms.</h1>
          <p className="section-lead">No paid APIs. Every figure on this site is built from free public data, processed in Python.</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner">
          <div className="fact reveal" style={{ '--d': '0ms', maxWidth: 720, marginBottom: '3rem' }}>
            <div className="fact-label">Stack</div>
            <div className="fact-value">Python, pandas, requests, BeautifulSoup, statsbombpy, matplotlib, mplsoccer, Playwright (for protected endpoints).</div>
          </div>

          <div className="data-grid">
            {sources.map(([t, bf, p], i) => (
              <div className="data-source reveal" key={t} style={{ '--d': `${i * 60}ms` }}>
                <h4>{t}</h4>
                <span className="best-for">Best for: {bf}</span>
                <p>{p}</p>
              </div>
            ))}
          </div>

          <div className="page-footer-cta">
            <a className="btn btn-primary" onClick={(e) => { e.preventDefault(); window.navigate('home'); }}>← Back to home</a>
            <a className="btn btn-secondary" onClick={(e) => { e.preventDefault(); window.navigate('visuals'); }}>See the visuals</a>
          </div>
        </div>
      </section>
    </>
  );
}

/* ============ CONTACT ============ */
function ContactPage() {
  return (
    <>
      <section className="page-hero">
        <div className="page-hero-inner">
          <span className="eyebrow">Contact</span>
          <h1>Get in touch.</h1>
          <p className="section-lead">Open to conversations about coaching, performance analysis, scouting, video analysis, opposition analysis — anything inside the game.</p>
        </div>
      </section>
      <section className="block">
        <div className="block-inner">
          <div className="contact-grid">
            <a className="contact-card reveal" style={{ '--d': '0ms' }} href="mailto:jaydon.coombs-goodfellow@outlook.com">
              <div className="contact-label">Email</div>
              <div className="contact-value">jaydon.coombs-goodfellow@outlook.com</div>
              <div className="contact-cta">Send a message →</div>
            </a>
            <a className="contact-card reveal" style={{ '--d': '100ms' }} href="https://www.linkedin.com/in/jaydoncoombsgoodfellow/" target="_blank" rel="noopener noreferrer">
              <div className="contact-label">LinkedIn</div>
              <div className="contact-value">Jaydon Coombs-Goodfellow</div>
              <div className="contact-cta">Connect →</div>
            </a>
          </div>
          <div className="page-footer-cta">
            <a className="btn btn-secondary" onClick={(e) => { e.preventDefault(); window.navigate('home'); }}>← Back to home</a>
          </div>
        </div>
      </section>
    </>
  );
}

Object.assign(window, { AboutPage, PhilosophyPage, AnalysisPage, VisualsPage, DataPage, ContactPage });
