/* Dünya Kupası 2026 — Maç Programı (TSİ) */
const { useState, useEffect, useMemo, useCallback, useRef } = React;

const ACCENT = "#E30A17";
const SITE_ORIGIN = "https://dunyakupasimaclari2026.com";

function pageAbsoluteUrl(path) {
  const p = path && path.startsWith("/") ? path : "/" + (path || "");
  if (typeof window !== "undefined" && window.location?.origin) {
    return window.location.origin + p;
  }
  return SITE_ORIGIN + p;
}

function factSharePath(factId) {
  if (!factId) return null;
  return "/bilgi/" + String(factId).toLowerCase() + "/";
}

function buildFactShare(playerName, teamName, factText, teamCode, imagePath, factId) {
  const path = teamUrl(teamCode) || "/";
  const pageUrl = pageAbsoluteUrl(path);
  const cardUrl = imagePath && factId ? pageAbsoluteUrl(factSharePath(factId)) : null;
  const imageUrl = imagePath ? pageAbsoluteUrl(imagePath) : null;
  let message = "⚽ " + playerName + " (" + teamName + ")\n" + factText;
  message += "\n\n" + (cardUrl || pageUrl);
  const shareUrl = cardUrl || imageUrl || pageUrl;
  const waUrl = "https://wa.me/?text=" + encodeURIComponent(message);
  const xUrl =
    "https://twitter.com/intent/tweet?text=" +
    encodeURIComponent(playerName + " — " + factText) +
    "&url=" +
    encodeURIComponent(shareUrl);
  return { message, pageUrl, imageUrl, imagePath, shareUrl, waUrl, xUrl };
}

async function shareFactWithImage(share) {
  if (!share?.imageUrl || typeof navigator.share !== "function") return false;
  try {
    const res = await fetch(share.imageUrl);
    if (!res.ok) return false;
    const blob = await res.blob();
    const file = new File([blob], "oyuncu-bilgi.png", { type: blob.type || "image/png" });
    const payload = { text: share.message, files: [file] };
    if (navigator.canShare && !navigator.canShare(payload)) {
      await navigator.share({ text: share.message, url: share.shareUrl });
      return true;
    }
    await navigator.share(payload);
    return true;
  } catch (err) {
    if (err?.name === "AbortError") return true;
    return false;
  }
}

function matchUrl(mt) {
  if (typeof WC_SEO === "undefined" || !mt?.id) return null;
  const slug = WC_SEO.matchSlug[mt.id];
  return slug ? "/mac/" + slug + "/" : null;
}

function teamUrl(code) {
  if (typeof WC_SEO === "undefined" || !code) return null;
  const slug = WC_SEO.teamSlug[code];
  return slug ? "/takim/" + slug + "/" : null;
}

function blogMatchUrl(mt) {
  if (typeof WC_SEO === "undefined" || !mt?.id) return null;
  const slug = WC_SEO.matchSlug[mt.id];
  return slug ? "/blog/mac/" + slug + "/" : null;
}

function blogDisplayName(mt) {
  if (!mt) return "";
  return "Dünya Kupası 2026 Grup " + mt.g + " " + WC.TEAMS[mt.h].ad + " – " + WC.TEAMS[mt.a].ad;
}

function searchNorm(text) {
  return String(text)
    .toLocaleLowerCase("tr")
    .replace(/ğ/g, "g")
    .replace(/ü/g, "u")
    .replace(/ş/g, "s")
    .replace(/ı/g, "i")
    .replace(/ö/g, "o")
    .replace(/ç/g, "c");
}

function buildSearchIndex() {
  const teamGroup = {};
  for (const [g, codes] of Object.entries(WC.GROUPS)) {
    for (const c of codes) teamGroup[c] = g;
  }
  const items = [];

  for (const [code, t] of Object.entries(WC.TEAMS)) {
    const href = teamUrl(code);
    if (!href) continue;
    const grp = teamGroup[code] || "";
    items.push({
      type: "team",
      typeLabel: "Takım",
      label: t.ad,
      sub: grp ? "Grup " + grp + " · Kadro ve maçlar" : "Kadro ve maçlar",
      href,
      iso: t.iso,
      q: searchNorm(t.ad + " " + code + " " + grp),
    });
  }

  for (const mt of WC.MATCHES) {
    const href = matchUrl(mt);
    if (!href) continue;
    const H = WC.TEAMS[mt.h];
    const A = WC.TEAMS[mt.a];
    items.push({
      type: "match",
      typeLabel: "Maç",
      label: H.ad + " – " + A.ad,
      sub: dayShort(mt.iso) + " " + hhmm(mt.iso) + " TSİ · Grup " + mt.g,
      href,
      q: searchNorm(H.ad + " " + A.ad + " " + mt.g + " " + mt.ven + " " + mt.city + " " + H.ad + A.ad),
    });
  }

  for (const g of Object.keys(WC.GROUPS).sort()) {
    const names = WC.GROUPS[g].map((c) => WC.TEAMS[c].ad).join(" ");
    items.push({
      type: "group",
      typeLabel: "Grup",
      label: "Grup " + g,
      sub: names,
      href: "/grup/" + g.toLowerCase() + "/",
      q: searchNorm("grup " + g + " " + names),
    });
  }

  [
    { label: "Bugün ve yarın", sub: "Yaklaşan maçlar", href: "/bugun/", q: "bugun yarin maclar" },
    { label: "Türkiye'nin maçları", sub: "A Millî fikstür (TSİ)", href: "/turkiye-maclari/", q: "turkiye mac millî a milli" },
    { label: "Turnuva ağacı", sub: "Eleme turu fikstürü", href: "/turnuva-agaci/", q: "turnuva agac eleme" },
    { label: "Blog", sub: "Rehberler ve önizlemeler", href: "/blog/", q: "blog rehber" },
    { label: "TRT uydu frekansları", sub: "Türksat 4A · 11794 · TRT 1 / Spor", href: "/blog/trt-dunya-kupasi-uydu-frekanslari/", q: "trt frekans uydu turksat yayin kanal" },
    { label: "Sıkça sorulan sorular", sub: "SSS", href: "/sss/", q: "sss soru sikca" },
  ].forEach((p) => {
    items.push({
      type: "page",
      typeLabel: "Sayfa",
      label: p.label,
      sub: p.sub,
      href: p.href,
      q: searchNorm(p.q + " " + p.label + " " + p.sub),
    });
  });

  return items;
}

let _searchIndex = null;
function getSearchIndex() {
  if (!_searchIndex) _searchIndex = buildSearchIndex();
  return _searchIndex;
}

function HeaderSearch() {
  const [q, setQ] = useState("");
  const [open, setOpen] = useState(false);
  const [active, setActive] = useState(0);
  const wrapRef = useRef(null);
  const listId = useMemo(() => "hd-search-list-" + Math.random().toString(36).slice(2, 9), []);

  const results = useMemo(() => {
    const raw = q.trim();
    if (raw.length < 2) return [];
    const tokens = searchNorm(raw).split(/\s+/).filter(Boolean);
    if (!tokens.length) return [];
    return getSearchIndex().filter((item) => tokens.every((t) => item.q.includes(t))).slice(0, 10);
  }, [q]);

  useEffect(() => {
    setActive(0);
    setOpen(q.trim().length >= 2 && results.length > 0);
  }, [q, results.length]);

  useEffect(() => {
    function onDoc(e) {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
    }
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, []);

  const onKeyDown = (e) => {
    if (!open || !results.length) {
      if (e.key === "Escape") setOpen(false);
      return;
    }
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setActive((i) => (i + 1) % results.length);
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setActive((i) => (i - 1 + results.length) % results.length);
    } else if (e.key === "Enter") {
      e.preventDefault();
      const item = results[active];
      if (item?.href) window.location.href = item.href;
    } else if (e.key === "Escape") {
      setOpen(false);
    }
  };

  return (
    <div className="hd-search" ref={wrapRef}>
      <label className="hd-search__label" htmlFor="hd-search-input">
        <span className="hd-search__icon" aria-hidden="true">
          <svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0016 9.5 6.5 6.5 0 109.5 16a6.471 6.471 0 004.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
        </span>
        <span className="sr-only">Takım veya maç ara</span>
      </label>
      <input
        id="hd-search-input"
        className="hd-search__input"
        type="search"
        role="combobox"
        aria-expanded={open}
        aria-controls={listId}
        aria-autocomplete="list"
        placeholder="Takım, maç ara…"
        autoComplete="off"
        spellCheck="false"
        value={q}
        onChange={(e) => setQ(e.target.value)}
        onFocus={() => { if (results.length >= 1 && q.trim().length >= 2) setOpen(true); }}
        onKeyDown={onKeyDown}
      />
      {open && results.length > 0 && (
        <ul className="hd-search__drop" id={listId} role="listbox">
          {results.map((item, i) => (
            <li key={item.type + "-" + (item.href || i)} role="option" aria-selected={i === active}>
              <a
                className={"hd-search__item" + (i === active ? " hd-search__item--on" : "")}
                href={item.href}
                onMouseEnter={() => setActive(i)}
                onClick={() => setOpen(false)}
              >
                {item.iso && (
                  <img className="hd-search__flag" src={flagUrl(item.iso, 40)} alt="" width="20" height="15" loading="lazy" decoding="async" />
                )}
                <span className="hd-search__body">
                  <span className="hd-search__row">
                    <span className="hd-search__label-t">{item.label}</span>
                    <span className={"hd-search__type hd-search__type--" + item.type}>{item.typeLabel}</span>
                  </span>
                  <span className="hd-search__sub">{item.sub}</span>
                </span>
              </a>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

const WD      = ["Paz","Pzt","Sal","Çar","Per","Cum","Cmt"];
const WD_LONG = ["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"];
const MON     = ["Oca","Şub","Mar","Nis","May","Haz","Tem","Ağu","Eyl","Eki","Kas","Ara"];

const dateKey = (iso) => iso.slice(0, 10);
const hhmm    = (iso) => iso.slice(11, 16);

function parts(iso) {
  const y = +iso.slice(0,4), mo = +iso.slice(5,7), da = +iso.slice(8,10);
  const wd = new Date(Date.UTC(y, mo - 1, da)).getUTCDay();
  return { y, mo, da, wd };
}
const dayLong  = (iso) => { const p = parts(iso); return `${p.da} ${MON[p.mo-1]} ${WD_LONG[p.wd]}`; };
const dayShort = (iso) => { const p = parts(iso); return `${p.da} ${MON[p.mo-1]} ${WD[p.wd]}`; };

let LIVE_OVERLAY = {};
let LIVE_KNOCKOUT = {};

function liveEntry(mt) {
  return LIVE_OVERLAY[mt.id];
}

function effectiveScore(mt) {
  const o = liveEntry(mt);
  const s = o?.s ?? mt.s;
  if (!s || !Array.isArray(s) || s.length < 2) return null;
  return s;
}

function statusOf(mt, now) {
  const o = liveEntry(mt);
  if (o?.status) return o.status;
  const ko = new Date(mt.iso).getTime();
  const t  = now.getTime();
  if (t < ko)              return "sched";
  if (t < ko + 130*60000) return "live";
  return "done";
}

function liveMinute(mt, now) {
  const o = liveEntry(mt);
  if (o?.minute) return o.minute;
  const el = (now.getTime() - new Date(mt.iso).getTime()) / 60000;
  if (el <= 45) return `${Math.max(1, Math.ceil(el))}'`;
  if (el <= 60) return "Devre arası";
  const mm = Math.min(90, Math.floor(el) - 15);
  return mm >= 90 ? "90'+" : `${mm}'`;
}

const SCORE_POLL_MS = 60 * 1000;

function useScoreFeed(onUpdate) {
  const load = useCallback(() => {
    fetch("/api/scores?t=" + Date.now())
      .then((r) => { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
      .then((data) => {
        if (data.error) throw new Error(data.error);
        LIVE_OVERLAY = data.matches || {};
        LIVE_KNOCKOUT = data.knockout || {};
        onUpdate?.();
      })
      .catch(() => {});
  }, [onUpdate]);

  useEffect(() => {
    load();
    const id = setInterval(load, SCORE_POLL_MS);
    return () => clearInterval(id);
  }, [load]);
}

function untilLabel(mt, now) {
  let s = Math.floor((new Date(mt.iso).getTime() - now.getTime()) / 1000);
  if (s <= 0) return "";
  const d = Math.floor(s / 86400); s -= d * 86400;
  const h = Math.floor(s / 3600);  s -= h * 3600;
  const mn = Math.floor(s / 60);
  if (d >= 1) return `${d} gün ${h} sa`;
  if (h >= 1) return `${h} sa ${mn} dk`;
  return `${mn} dk`;
}

const MATCH_DURATION_MS = 120 * 60000;

function icsEscape(s) {
  return String(s).replace(/\\/g, "\\\\").replace(/;/g, "\\;").replace(/,/g, "\\,").replace(/\n/g, "\\n");
}

function formatICSDateUTC(d) {
  return d.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}/, "");
}

function matchEventData(mt) {
  const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
  const start = new Date(mt.iso);
  const end = new Date(start.getTime() + MATCH_DURATION_MS);
  const title = `DK 2026: ${H.ad} – ${A.ad}`;
  const desc = `Grup ${mt.g} · ${mt.md}. maç günü\nYayın: ${mt.ch}\nSaat: TSİ (GMT+3)`;
  const loc = `${mt.ven}, ${mt.city}, ${mt.country}`;
  return { start, end, title, desc, loc, uid: mt.id + "@dunyakupasi2026" };
}

function buildICS(matches) {
  const list = Array.isArray(matches) ? matches : [matches];
  const stamp = formatICSDateUTC(new Date());
  const events = list.map((mt) => {
    const { start, end, title, desc, loc, uid } = matchEventData(mt);
    return [
      "BEGIN:VEVENT",
      "UID:" + uid,
      "DTSTAMP:" + stamp,
      "DTSTART:" + formatICSDateUTC(start),
      "DTEND:" + formatICSDateUTC(end),
      "SUMMARY:" + icsEscape(title),
      "DESCRIPTION:" + icsEscape(desc),
      "LOCATION:" + icsEscape(loc),
      "END:VEVENT",
    ].join("\r\n");
  }).join("\r\n");
  return ["BEGIN:VCALENDAR", "VERSION:2.0", "PRODID:-//Dunya Kupasi 2026//TR", "CALSCALE:GREGORIAN", "METHOD:PUBLISH", events, "END:VCALENDAR"].join("\r\n");
}

function downloadICS(matches, filename) {
  const blob = new Blob([buildICS(matches)], { type: "text/calendar;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 2000);
}

function openICSNative(matches) {
  const blob = new Blob([buildICS(matches)], { type: "text/calendar;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.style.display = "none";
  document.body.appendChild(a);
  a.click();
  a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 60000);
}

function openGoogleCalendar(mt) {
  const { start, end, title, desc, loc } = matchEventData(mt);
  const dates = formatICSDateUTC(start) + "/" + formatICSDateUTC(end);
  const params = new URLSearchParams({ action: "TEMPLATE", text: title, dates, details: desc, location: loc });
  window.open("https://calendar.google.com/calendar/render?" + params.toString(), "_blank", "noopener,noreferrer");
}

function calendarPlatform() {
  const ua = navigator.userAgent;
  if (/iPhone|iPad|iPod/i.test(ua)) return "ios";
  if (/Android/i.test(ua)) return "android";
  if (/Macintosh|Mac OS X/i.test(ua)) return "macos";
  return "other";
}

function calendarHint(platform) {
  if (platform === "ios") return "Apple Takvim uygulamasına eklenir.";
  if (platform === "android") return "Google Takvim veya varsayılan takvim uygulamanız açılır.";
  if (platform === "macos") return "macOS Takvim uygulamasında içe aktarma penceresi açılır.";
  return ".ics dosyası Apple Takvim, Outlook ve Google ile uyumludur.";
}

function prepareCalList(matches, opts, now) {
  const arr = Array.isArray(matches) ? matches : [matches];
  if (opts.allProgram) return arr.slice();
  const t = now || new Date();
  return arr.filter((m) => statusOf(m, t) === "sched");
}

async function shareICSFile(matches, filename) {
  try {
    const file = new File([buildICS(matches)], filename, { type: "text/calendar;charset=utf-8" });
    if (navigator.share && navigator.canShare && navigator.canShare({ files: [file] })) {
      await navigator.share({ files: [file], title: "Dünya Kupası 2026" });
      return true;
    }
  } catch (e) { /* kullanıcı iptal */ }
  return false;
}

async function addToCalendar(matches, opts, now) {
  const o = opts || {};
  const list = prepareCalList(matches, o, now);
  if (!list.length) return;
  const platform = calendarPlatform();
  const fname = list.length === 1 ? "dk2026-" + list[0].id + ".ics" : "dk2026-maclar.ics";

  if (platform === "ios" || platform === "macos") {
    if (await shareICSFile(list, fname)) return;
    if (platform === "macos") { openICSNative(list); return; }
    downloadICS(list, fname);
    return;
  }
  if (platform === "android") {
    if (list.length === 1) openGoogleCalendar(list[0]);
    else downloadICS(list, fname);
    return;
  }
  downloadICS(list, fname);
}

function CalIcon({ size }) {
  const s = size || 18;
  return (
    <svg viewBox="0 0 24 24" width={s} height={s} aria-hidden="true">
      <rect x="3" y="4" width="18" height="18" rx="2.5" fill="currentColor" opacity=".14" />
      <rect x="3" y="4" width="18" height="18" rx="2.5" fill="none" stroke="currentColor" strokeWidth="2" />
      <path d="M3 10h18" stroke="currentColor" strokeWidth="2" />
      <path d="M8 2.5v3M16 2.5v3" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
      <path d="M12 13.5v3M10.5 15h3" stroke="currentColor" strokeWidth="1.85" strokeLinecap="round" />
    </svg>
  );
}

function ChannelBadge({ channel, compact }) {
  if (!channel) return null;
  const b = WC.BROADCASTERS && WC.BROADCASTERS[channel];
  return (
    <span className={"ch-badge" + (compact ? " ch-badge--sm" : "")} title={"Yayın: " + channel}>
      {b && b.logo ? (
        <img
          className="ch-badge__logo"
          src={b.logo}
          alt={channel}
          width={b.w || 64}
          height={b.h || 20}
          loading="lazy"
          decoding="async"
        />
      ) : (
        <span className="ch-badge__name">{channel}</span>
      )}
    </span>
  );
}

function CalMatchBtn({ mt, now }) {
  if (statusOf(mt, now) !== "sched") return null;
  const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
  return (
    <button type="button" className="cal-pill"
      onClick={(e) => { e.stopPropagation(); addToCalendar([mt], {}, now); }}
      aria-label={`${H.ad} – ${A.ad} maçını takvime ekle`}>
      <CalIcon size={18} />
      <span className="cal-pill__txt">Takvim</span>
    </button>
  );
}

function AddToCalendar({ matches, compact, icon, now, allProgram, labelPrefix }) {
  const list = useMemo(() => prepareCalList(matches, { allProgram }, now), [matches, allProgram, now]);
  if (!list.length) return null;

  const platform = calendarPlatform();
  const label = labelPrefix
    ? `${labelPrefix} (${list.length})`
    : list.length === 1 ? "Takvime ekle" : `Takvime ekle (${list.length})`;

  const onPrimary = (e) => { e.stopPropagation(); addToCalendar(list, { allProgram }, now); };
  const onGoogle = (e) => { e.stopPropagation(); if (list.length === 1) openGoogleCalendar(list[0]); };

  if (icon) {
    return (
      <button type="button" className="calico" onClick={onPrimary} aria-label={label} title={label}>
        <CalIcon size={18} />
      </button>
    );
  }

  return (
    <div className={"cal" + (compact ? " cal--compact" : "")} onClick={(e) => e.stopPropagation()}>
      <button type="button" className={"calbtn" + (compact ? " calbtn--sm" : "")} onClick={onPrimary} aria-label={label}>
        <CalIcon />{label}
      </button>
      {platform === "other" && list.length === 1 && (
        <button type="button" className="calbtn calbtn--ghost calbtn--sm" onClick={onGoogle}>Google</button>
      )}
    </div>
  );
}

function computeTable(group, matches, now) {
  const rows = {};
  WC.GROUPS[group].forEach((c) => (rows[c] = { code: c, O:0, G:0, B:0, M:0, AG:0, YG:0, P:0 }));
  matches
    .filter((m) => m.g === group && effectiveScore(m) && statusOf(m, now) === "done")
    .forEach((m) => {
      const [hg, ag] = effectiveScore(m);
      const H = rows[m.h], A = rows[m.a];
      H.O++; A.O++; H.AG += hg; H.YG += ag; A.AG += ag; A.YG += hg;
      if (hg > ag)      { H.G++; A.M++; H.P += 3; }
      else if (hg < ag) { A.G++; H.M++; A.P += 3; }
      else              { H.B++; A.B++; H.P++;     A.P++; }
    });
  return Object.values(rows).sort((a, b) =>
    b.P - a.P || (b.AG - b.YG) - (a.AG - a.YG) || b.AG - a.AG ||
    WC.TEAMS[a.code].ad.localeCompare(WC.TEAMS[b.code].ad, "tr")
  );
}

function usePersist(key, init) {
  const [v, setV] = useState(() => {
    try { const r = localStorage.getItem(key); return r === null ? init : JSON.parse(r); }
    catch (e) { return init; }
  });
  useEffect(() => { try { localStorage.setItem(key, JSON.stringify(v)); } catch (e) {} }, [key, v]);
  return [v, setV];
}

/* ---- small components ---- */
function flagUrl(iso, w) {
  return "https://flagcdn.com/w" + w + "/" + iso + ".png";
}

function Badge({ code, fav, size }) {
  const t = WC.TEAMS[code];
  if (!t) return <span className="badge">{code}</span>;
  if (t.iso) {
    const w = size === "sheet" ? 80 : size === "tree" ? 40 : 80;
    return (
      <span className={"flag" + (fav ? " flag--fav" : "") + (size ? " flag--" + size : "")} title={t.ad}>
        <img src={flagUrl(t.iso, w)} alt="" loading="lazy" decoding="async" />
      </span>
    );
  }
  return <span className={"badge" + (fav ? " badge--fav" : "")}>{code}</span>;
}

function Star({ on, onClick }) {
  return (
    <button className={"star" + (on ? " star--on" : "")}
      onClick={(e) => { e.stopPropagation(); onClick(); }} aria-label={on ? "Favorilerden çıkar" : "Favorilere ekle"}>
      <svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true">
        <path d="M12 3.6l2.6 5.27 5.82.85-4.21 4.1.99 5.79L12 17.9l-5.2 2.73.99-5.79-4.21-4.1 5.82-.85z"
          fill={on ? "currentColor" : "none"} stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />
      </svg>
    </button>
  );
}

function StatusPill({ st, mt, now }) {
  if (st === "live") return <span className="pill pill--live" role="status"><span className="dot" aria-hidden="true" />CANLI · {liveMinute(mt, now)}</span>;
  if (st === "done") return <span className="pill pill--done">BİTTİ</span>;
  return <span className="pill pill--sched">Başlamadı</span>;
}

/* ---- match card ---- */
function teamGroup(code) {
  for (const [g, arr] of Object.entries(WC.GROUPS)) {
    if (arr.includes(code)) return g;
  }
  return null;
}

function TeamNameBtn({ code, className, onOpenTeam }) {
  const t = WC.TEAMS[code];
  const href = teamUrl(code);
  const hasSquad = typeof WC_SQUADS !== "undefined" && WC_SQUADS.byTeam[code];
  if (href && hasSquad) {
    return (
      <a className={"teamlink" + (className ? " " + className : "")} href={href}
        onClick={(e) => e.stopPropagation()} aria-label={t.ad + " kadrosu ve maçları"}>
        {t.ad}
      </a>
    );
  }
  if (!hasSquad || !onOpenTeam) return <span className={className}>{t.ad}</span>;
  return (
    <button type="button" className={"teamlink" + (className ? " " + className : "")}
      onClick={(e) => { e.stopPropagation(); onOpenTeam(code); }}
      aria-label={t.ad + " kadrosu"}>
      {t.ad}
    </button>
  );
}

function TeamRow({ code, score, st, win, fav, onFav, onOpenTeam }) {
  const t = WC.TEAMS[code];
  const losing = st !== "sched" && score != null && !win;
  return (
    <div className={"team" + (win ? " team--win" : "") + (losing ? " team--lose" : "")}>
      <Star on={fav} onClick={onFav} />
      <Badge code={code} fav={fav} />
      <span className="tname"><TeamNameBtn code={code} onOpenTeam={onOpenTeam} /></span>
      {st !== "sched" && score != null
        ? <span className="score">{score}</span>
        : <span className="score score--empty">–</span>}
    </div>
  );
}

function MatchCard({ mt, now, favs, toggleFav, onOpen, onOpenTeam, nextUp }) {
  const st = statusOf(mt, now);
  const sc = effectiveScore(mt);
  const winH = st !== "sched" && sc && sc[0] > sc[1];
  const winA = st !== "sched" && sc && sc[1] > sc[0];
  const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
  const label = st === "done" && sc
    ? `${H.ad} ${sc[0]} – ${sc[1]} ${A.ad}, Grup ${mt.g}, ${hhmm(mt.iso)}`
    : `${H.ad} – ${A.ad}, Grup ${mt.g}, ${hhmm(mt.iso)}` + (nextUp ? ", sıradaki maç" : "");
  const href = matchUrl(mt);
  const open = () => { if (href) window.location.href = href; else onOpen(mt); };
  const cls = "match match--" + st + (nextUp ? " match--next" : "");
  const inner = (
    <React.Fragment>
      <div className="match__main">
        <div className="meta">
          <span className="meta__grp">Grup {mt.g}</span>
          <span className="meta__sep">·</span>
          <span className="meta__ven">{mt.city}</span>
          {mt.ch && (
            <React.Fragment>
              <span className="meta__sep">·</span>
              <ChannelBadge channel={mt.ch} />
            </React.Fragment>
          )}
          <CalMatchBtn mt={mt} now={now} />
        </div>
        <TeamRow code={mt.h} score={sc && sc[0]} st={st} win={winH} fav={favs.includes(mt.h)} onFav={() => toggleFav(mt.h)} onOpenTeam={onOpenTeam} />
        <TeamRow code={mt.a} score={sc && sc[1]} st={st} win={winA} fav={favs.includes(mt.a)} onFav={() => toggleFav(mt.a)} onOpenTeam={onOpenTeam} />
      </div>
      <div className="match__side">
        {mt.ch && (
          <span className="match__side-ch">
            <ChannelBadge channel={mt.ch} compact />
          </span>
        )}
        {nextUp && <span className="match__tag">Sırada</span>}
        <div className="match__time">{hhmm(mt.iso)}</div>
        <StatusPill st={st} mt={mt} now={now} />
        {st === "sched" && <div className="match__until">{untilLabel(mt, now)}</div>}
      </div>
    </React.Fragment>
  );
  if (href) {
    return <a href={href} className={cls} aria-label={label}>{inner}</a>;
  }
  return (
    <article className={cls} onClick={open} tabIndex={0} role="button" aria-label={label}
      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); open(); } }}>
      {inner}
    </article>
  );
}

/* ---- date strip ---- */
function DateStrip({ dates, value, onChange, todayKey, now }) {
  const stripRef = React.useRef(null);
  const programCal = useMemo(
    () => prepareCalList(WC.MATCHES, { allProgram: true }, now),
    [now]
  );
  useEffect(() => {
    const el = stripRef.current?.querySelector(".chip--today");
    el?.scrollIntoView({ inline: "center", block: "nearest", behavior: "smooth" });
  }, [todayKey]);
  const onAllDays = () => onChange("all");
  const onProgramCal = (e) => {
    e.stopPropagation();
    if (programCal.length) addToCalendar(programCal, { allProgram: true }, now);
  };
  return (
    <div className="strip-wrap">
      <div className="strip" role="tablist" aria-label="Gün seçimi" ref={stripRef}>
      <div className={"chip chip--wide chip--split chip--all" + (value === "all" ? " chip--on" : "")}>
        <button type="button" role="tab" aria-selected={value === "all"} className="chip__tab" onClick={onAllDays}>
          Tüm günler
        </button>
        {programCal.length > 0 && (
          <button
            type="button"
            className="chip__cal"
            onClick={onProgramCal}
            aria-label={`Takvime ekle: tüm program, ${programCal.length} maç`}
            title={`Tüm programı takvime ekle (${programCal.length} maç, .ics)`}
          >
            <CalIcon size={20} />
          </button>
        )}
      </div>
      {dates.map((dk) => {
        const iso = dk + "T00:00:00+03:00";
        const p = parts(iso);
        const isToday = dk === todayKey;
        return (
          <button key={dk} role="tab" aria-selected={value === dk}
            className={"chip chip--date" + (value === dk ? " chip--on" : "") + (isToday ? " chip--today" : "")}
            onClick={() => onChange(dk)}>
            <span className="chip__wd">{WD[p.wd]}{isToday && <i className="todot" aria-hidden="true" />}</span>
            <span className="chip__d">{p.da}</span>
            <span className="chip__mo">{MON[p.mo-1]}</span>
          </button>
        );
      })}
      </div>
    </div>
  );
}

/* ---- HairSimulate reklam ---- */
const HAIRSIM_URL = "https://hairsimulate.com";
const HAIRSIM_LOGO = "/hairsim-logo.png";
const HAIRSIM_BEFORE = "https://hairsimulate.com/images/landing-before.webp";
const HAIRSIM_AFTER = "https://hairsimulate.com/images/landing-after.webp";

function SiteAdPromo() {
  return (
    <div className="ad-promo">
      <div className="ad-promo__inner">
        <HairSimBanner />
      </div>
    </div>
  );
}

function XPromoIcon({ size = 22 }) {
  return (
    <svg className="x-promo__icon" viewBox="0 0 24 24" width={size} height={size} aria-hidden="true">
      <path
        fill="currentColor"
        d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
      />
    </svg>
  );
}

function SiteXPromo() {
  const x = WC.X;
  if (!x) return null;
  const href = x.url && x.url.trim();
  if (!href) return null;
  return (
    <aside className="x-promo" aria-label="X hesabı">
      <div className="x-promo__inner">
        <div className="x-promo__copy">
          <XPromoIcon size={22} />
          <div>
            <p className="x-promo__cta">{x.cta}</p>
            <p className="x-promo__sub">{x.sub}</p>
          </div>
        </div>
        <a className="x-promo__btn" href={href} target="_blank" rel="noopener noreferrer">
          {x.btn}
        </a>
      </div>
    </aside>
  );
}

function SiteFooter() {
  return (
    <footer className="foot">
      Saatler Türkiye (TSİ / GMT+3) üzerinden gösterilir · Yayıncı bilgisi (TRT) gösterim amaçlıdır · Fikstür: FIFA resmî programı · <a className="foot__wa" href="/blog/">Blog</a> · <a className="foot__wa" href="/sss/">SSS</a>
    </footer>
  );
}

function HairSimBanner() {
  return (
    <aside className="ad-banner" aria-label="İşbirliği reklamı">
      <a
        className="ad-banner__link"
        href={HAIRSIM_URL}
        target="_blank"
        rel="noopener noreferrer sponsored"
        aria-label="HairSimulate işbirliği — önce ve sonra AI saç ekimi önizlemesi, ücretsiz dene"
      >
        <span className="ad-banner__badge">İşbirliği</span>
        <div className="ad-banner__col ad-banner__col--content">
          <div className="ad-banner__ba">
            <div className="ad-banner__brand">
              <img
                className="ad-banner__logo"
                src={HAIRSIM_LOGO}
                alt="HairSimulate"
                width="200"
                height="64"
                loading="lazy"
                decoding="async"
              />
            </div>
            <div className="ad-banner__shots">
              <figure className="ad-banner__shot">
                <img src={HAIRSIM_BEFORE} alt="" width="96" height="96" loading="lazy" decoding="async" />
                <figcaption>Önce</figcaption>
              </figure>
              <span className="ad-banner__ba-arrow">→</span>
              <figure className="ad-banner__shot">
                <img src={HAIRSIM_AFTER} alt="" width="96" height="96" loading="lazy" decoding="async" />
                <figcaption>Sonra</figcaption>
              </figure>
            </div>
          </div>
          <div className="ad-banner__copy">
            <strong className="ad-banner__title">Tek fotoğrafla AI saç ekimi önizlemesi</strong>
            <span className="ad-banner__sub">Ücretsiz dene · hairsimulate.com</span>
          </div>
        </div>
        <div className="ad-banner__col ad-banner__col--cta">
          <span className="ad-banner__cta" aria-hidden="true">Keşfet</span>
        </div>
      </a>
    </aside>
  );
}

/* ---- filter bar ---- */
const GROUP_KEYS = ["A","B","C","D","E","F","G","H","I","J","K","L"];
function FilterBar({ group, setGroup, status, setStatus, favOnly, setFavOnly, favCount, hasFilters, onReset, matchCount }) {
  return (
    <div className="filters">
      <div className="filters__top">
        <div className="filters__legend" aria-hidden="true">
          <span><i className="i-live" />Canlı maç</span>
          <span><i className="i-next" />Sıradaki maç</span>
        </div>
        {hasFilters && (
          <button type="button" className="filters__clear" onClick={onReset}>Filtreleri temizle</button>
        )}
      </div>
      <div className="grpchips" role="group" aria-label="Grup filtresi">
        <button aria-pressed={group === "all"} className={"gchip gchip--all" + (group === "all" ? " gchip--on" : "")} onClick={() => setGroup("all")}>Tümü</button>
        {GROUP_KEYS.map((g) => (
          <button key={g} aria-pressed={group === g} aria-label={"Grup " + g} className={"gchip" + (group === g ? " gchip--on" : "")} onClick={() => setGroup(g)}>{g}</button>
        ))}
      </div>
      <div className="filters__right">
        <div className="seg" role="group" aria-label="Maç durumu">
          {[["all","Tümü"],["live","Canlı"],["sched","Yaklaşan"],["done","Biten"]].map(([k,l]) => (
            <button key={k} aria-pressed={status === k} className={"seg__b" + (status === k ? " seg__b--on" : "")} onClick={() => setStatus(k)}>{l}</button>
          ))}
        </div>
        <button aria-pressed={favOnly} className={"favbtn" + (favOnly ? " favbtn--on" : "")} onClick={() => setFavOnly(!favOnly)}>
          <svg viewBox="0 0 24 24" width="14" height="14">
            <path d="M12 3.6l2.6 5.27 5.82.85-4.21 4.1.99 5.79L12 17.9l-5.2 2.73.99-5.79-4.21-4.1 5.82-.85z"
              fill={favOnly ? "currentColor" : "none"} stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" />
          </svg>
          Favorilerim{favCount ? ` · ${favCount}` : ""}
        </button>
      </div>
      {matchCount != null && (
        <p className="filters__legend" style={{ margin: 0 }}>{matchCount} maç listeleniyor</p>
      )}
    </div>
  );
}

/* ---- standings table ---- */
function MiniTable({ group, now, favs, onOpenTeam }) {
  const tbl = computeTable(group, WC.MATCHES, now);
  return (
    <table className="tbl">
      <caption>Grup {group} puan durumu</caption>
      <thead>
        <tr>
          <th className="tbl__pos" scope="col"></th>
          <th className="tbl__team" scope="col">Takım</th>
          <th scope="col" title="Oynanan">O</th>
          <th className="tbl__hide" scope="col" title="Galibiyet">G</th>
          <th className="tbl__hide" scope="col" title="Beraberlik">B</th>
          <th className="tbl__hide" scope="col" title="Mağlubiyet">M</th>
          <th scope="col" title="Averaj">Av</th>
          <th scope="col" title="Puan">P</th>
        </tr>
      </thead>
      <tbody>
        {tbl.map((r, i) => {
          const av = r.AG - r.YG;
          const cls = (i < 2 ? "qual" : i === 2 ? "qual3" : "") + (favs.includes(r.code) ? " favrow" : "");
          return (
            <tr key={r.code} className={cls}>
              <td className="tbl__pos">
                <span className="tbl__pos-in">
                  <span className={"posdot p" + (i+1)} />
                  <span>{i+1}</span>
                </span>
              </td>
              <td className="tbl__team">
                <span className="tbl__team-in">
                  <Badge code={r.code} fav={favs.includes(r.code)} size="tbl" />
                  <TeamNameBtn code={r.code} onOpenTeam={onOpenTeam} />
                </span>
              </td>
              <td>{r.O}</td>
              <td className="tbl__hide">{r.G}</td>
              <td className="tbl__hide">{r.B}</td>
              <td className="tbl__hide">{r.M}</td>
              <td className="av">{av > 0 ? "+" + av : av}</td>
              <td className="pts">{r.P}</td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

/* ---- turnuva ağacı (FIFA şeması + canlı fikstür) ---- */
function BracketTreeColumn({ col, rowCount, now, showConnector }) {
  const isCenter = col.side === "center";
  const isFinal = col.roundId === "final";
  const isThird = col.roundId === "third";
  return (
    <section
      className={
        "bracket-tree__col" +
        (isCenter ? " bracket-tree__col--center" : "") +
        (col.side === "right" ? " bracket-tree__col--right" : "") +
        (isFinal ? " bracket-tree__col--final" : "") +
        (isThird ? " bracket-tree__col--third" : "")
      }
      style={{ "--brk-rows": isThird ? rowCount : rowCount }}
      aria-labelledby={"brk-h-" + col.roundId + "-" + col.side}
    >
      <h3 className="bracket-tree__col-h" id={"brk-h-" + col.roundId + "-" + col.side}>
        {col.label}
      </h3>
      {col.cells.map((cell) => (
        <div
          key={cell.key}
          className={
            "brkt-cell" +
            (showConnector ? " brkt-cell--link" : "") +
            " brkt-cell--span-" + cell.rowSpan
          }
          style={{ "--rs": cell.rowStart, "--rsp": cell.rowSpan }}
        >
          {cell.mt && <BracketMatch mt={cell.mt} now={now} compact={!isFinal} />}
        </div>
      ))}
    </section>
  );
}

function useBracketFeed() {
  const [feed, setFeed] = useState(null);
  const [err, setErr] = useState(null);
  const [loading, setLoading] = useState(true);
  const [fetchedAt, setFetchedAt] = useState(null);

  const load = useCallback(() => {
    setLoading(true);
    setErr(null);
    fetch(WC_BRACKET.FEED_URL + "?t=" + Date.now())
      .then((r) => { if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); })
      .then((json) => {
        setFeed(WC_BRACKET.parseFeed(json));
        setFetchedAt(new Date());
      })
      .catch((e) => setErr(e.message || "Veri alınamadı"))
      .finally(() => setLoading(false));
  }, []);

  useEffect(() => {
    load();
    const id = setInterval(load, 30 * 60000);
    return () => clearInterval(id);
  }, [load]);

  return { feed, err, loading, fetchedAt, refresh: load };
}

function BracketTeam({ side, score, win, lose }) {
  const isSlot = side.type === "slot" || side.type === "name" || side.type === "tbd";
  return (
    <div className={"brk__team" + (win ? " brk__team--win" : "") + (lose ? " brk__team--lose" : "")}>
      <span className={isSlot ? "brk__slot" : "brk__name"}>
        {side.code && !isSlot && <Badge code={side.code} size="tree" />}
        <span className="brk__label">{side.label}</span>
      </span>
      {score != null && <span className="brk__sc">{score}</span>}
    </div>
  );
}

function BracketMatch({ mt, now, compact }) {
  const hasTime = mt.iso && mt.iso.length >= 16;
  return (
    <article className={"brk" + (compact ? " brk--tree" : "") + " brk--" + mt.st}>
      {mt.num != null && <div className="brk__num">Maç {mt.num}</div>}
      <BracketTeam side={mt.side1} score={mt.score ? mt.score[0] : null} win={mt.win1} lose={mt.win2 && !mt.win1} />
      <BracketTeam side={mt.side2} score={mt.score ? mt.score[1] : null} win={mt.win2} lose={mt.win1 && !mt.win2} />
      {!compact && (
        <div className="brk__foot">
          {hasTime && <span>{dayLong(mt.iso)} · {hhmm(mt.iso)} TSİ</span>}
          {mt.venue && <span>{mt.venue}</span>}
        </div>
      )}
      {compact && hasTime && (
        <div className="brk__foot brk__foot--mini">
          <span className="brk__date">{dayShort(mt.iso)}</span>
          <span className="brk__time">{hhmm(mt.iso)} TSİ</span>
        </div>
      )}
      {!compact && (
        <div className="brk__st"><StatusPill st={mt.st} mt={{ iso: mt.iso, s: mt.score }} now={now} /></div>
      )}
      {compact && mt.st === "live" && (
        <div className="brk__st brk__st--mini"><StatusPill st={mt.st} mt={{ iso: mt.iso, s: mt.score }} now={now} /></div>
      )}
    </article>
  );
}

function BracketView({ now, scoreTick }) {
  const { feed, err, loading, fetchedAt, refresh } = useBracketFeed();
  const standings = useMemo(() => {
    const s = {};
    GROUP_KEYS.forEach((g) => { s[g] = computeTable(g, WC.MATCHES, now); });
    return s;
  }, [now, scoreTick]);

  const tree = useMemo(() => {
    if (!feed) return null;
    const byNum = { ...feed.byNum };
    for (const [key, o] of Object.entries(LIVE_KNOCKOUT)) {
      if (!byNum[key] || !o?.s) continue;
      byNum[key] = { ...byNum[key], score1: o.s[0], score2: o.s[1] };
    }
    return WC_BRACKET.enrichKnockout(byNum, standings, WC.TEAMS, WC.MATCHES, now, statusOf);
  }, [feed, standings, now, scoreTick]);

  const updatedLabel = fetchedAt
    ? fetchedAt.toLocaleString("tr-TR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit", timeZone: "Europe/Istanbul" }) + " TSİ"
    : "";

  return (
    <div className="bracket-view">
      <div className="bracket-hd">
        <div>
          <h2 className="bracket-hd__title">Turnuva ağacı</h2>
          <p className="bracket-hd__sub">
            FIFA turnuva ağacı düzeni; tarih ve stadyum openfootball fikstüründen gelir (30 dk’da bir yenilenir).
            Grup 1./2. sıraları, o grupta en az bir maç bittikten sonra yerel puan durumundan doldurulur.
          </p>
          {updatedLabel && <p className="bracket-hd__meta">Son güncelleme: {updatedLabel}</p>}
          {window.WC_PAGE?.type !== "bracket" && (
            <p className="bracket-hd__meta"><a href="/turnuva-agaci/">Format, SSS ve Türkiye’nin yolu →</a></p>
          )}
        </div>
        <div className="bracket-hd__actions">
          <button type="button" className="bracket-refresh" onClick={refresh} disabled={loading}>
            {loading ? "Yükleniyor…" : "Yenile"}
          </button>
        </div>
      </div>

      {err && (
        <div className="bracket-err">
          Canlı fikstür yüklenemedi: {err}
          <br />
          <button type="button" className="bracket-refresh" onClick={refresh}>Tekrar dene</button>
        </div>
      )}

      {loading && !tree && !err && <p className="filters__legend">Fikstür yükleniyor…</p>}

      {tree && (
        <div className="bracket-scroll" role="region" aria-label="Eleme turu şeması">
          <p className="bracket-scroll-hint" aria-hidden="true">Kaydırarak tüm turları görün · mobilde tur başına hizalanır</p>
          <div className="bracket-tree" style={{ "--brk-rows": tree.rowCount }}>
            <div className="bracket-tree__half bracket-tree__half--left">
              {tree.left.map((col, i) => (
                <BracketTreeColumn
                  key={"L-" + col.roundId}
                  col={col}
                  rowCount={tree.rowCount}
                  now={now}
                  showConnector={true}
                />
              ))}
            </div>
            <div className="bracket-tree__center-wrap">
              {tree.center.map((col) => (
                <BracketTreeColumn
                  key={"C-" + col.roundId}
                  col={col}
                  rowCount={tree.rowCount}
                  now={now}
                  showConnector={false}
                />
              ))}
            </div>
            <div className="bracket-tree__half bracket-tree__half--right">
              {tree.right.map((col) => (
                <BracketTreeColumn
                  key={"R-" + col.roundId}
                  col={col}
                  rowCount={tree.rowCount}
                  now={now}
                  showConnector={true}
                />
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function GroupsView({ now, favs, onOpenTeam }) {
  return (
    <div className="grpgrid">
      {GROUP_KEYS.map((g) => {
        const played = WC.MATCHES.filter((m) => m.g === g && statusOf(m, now) === "done").length;
        const pct = Math.round((played / 6) * 100);
        return (
          <section className="grpcard" key={g}>
            <header className="grpcard__h">
              <h3>{window.WC_PAGE?.type === "group" && window.WC_PAGE.group === g ? `Grup ${g}` : <a className="grpcard__link" href={"/grup/" + g.toLowerCase() + "/"}>Grup {g}</a>}</h3>
              <div className="grpcard__meta">
                <span className="grpcard__cnt">{played}/6 maç</span>
                <div className="grpcard__prog" aria-hidden="true"><i style={{ width: pct + "%" }} /></div>
              </div>
            </header>
            <MiniTable group={g} now={now} favs={favs} onOpenTeam={onOpenTeam} />
          </section>
        );
      })}
      <p className="qual-note">
        <span className="posdot p1" /> İlk 2 sıra üst tura çıkar &nbsp;·&nbsp;
        <span className="posdot p3" /> En iyi 8 üçüncü de üst tura kalır
      </p>
    </div>
  );
}

/* ---- bugün / yarın maçları ---- */
function istanbulDateKey(d) {
  const ist = new Date(d.getTime() + 3 * 3600000);
  const y  = ist.getUTCFullYear();
  const mo = String(ist.getUTCMonth() + 1).padStart(2, "0");
  const da = String(ist.getUTCDate()).padStart(2, "0");
  return `${y}-${mo}-${da}`;
}

function shiftDateKey(key, days) {
  const d = new Date(key + "T12:00:00Z");
  d.setUTCDate(d.getUTCDate() + days);
  return istanbulDateKey(d);
}

function TodayMatchGroup({ title, dayKey, matches, now, favs, toggleFav, onOpenTeam }) {
  const noop = () => {};
  return (
    <section className="today-group">
      <h2 className="today-group__h">{title} <span className="today-group__date">{dayShort(dayKey + "T12:00:00+03:00")}</span></h2>
      {matches.length ? (
        <div className="list">
          {matches.map((mt) => (
            <MatchCard key={mt.id} mt={mt} now={now} favs={favs} toggleFav={toggleFav} onOpen={noop} onOpenTeam={onOpenTeam} />
          ))}
        </div>
      ) : (
        <p className="today-group__empty">Bu tarihte planlanmış Dünya Kupası maçı yok.</p>
      )}
    </section>
  );
}

function TodayMatchesView({ now, favs, toggleFav, onOpenTeam }) {
  const todayKey = istanbulDateKey(now);
  const tomorrowKey = shiftDateKey(todayKey, 1);
  const byDay = (key) => WC.MATCHES.filter((m) => dateKey(m.iso) === key).sort((a, b) => a.iso.localeCompare(b.iso));

  return (
    <div className="today-view">
      <TodayMatchGroup title="Bugün" dayKey={todayKey} matches={byDay(todayKey)} now={now} favs={favs} toggleFav={toggleFav} onOpenTeam={onOpenTeam} />
      <TodayMatchGroup title="Yarın" dayKey={tomorrowKey} matches={byDay(tomorrowKey)} now={now} favs={favs} toggleFav={toggleFav} onOpenTeam={onOpenTeam} />
    </div>
  );
}

function TurkeyMatchesView({ now, favs, toggleFav, onOpenTeam }) {
  const noop = () => {};
  const matches = WC.MATCHES
    .filter((m) => m.h === "TUR" || m.a === "TUR")
    .sort((a, b) => a.iso.localeCompare(b.iso));
  return (
    <section className="today-group">
      <h2 className="today-group__h">Türkiye'nin maçları</h2>
      <div className="list">
        {matches.map((mt) => (
          <MatchCard key={mt.id} mt={mt} now={now} favs={favs} toggleFav={toggleFav} onOpen={noop} onOpenTeam={onOpenTeam} />
        ))}
      </div>
    </section>
  );
}

function VenueMatchesView({ venueKey, now, favs, toggleFav, onOpenTeam }) {
  const noop = () => {};
  const [venue, city] = String(venueKey || "").split("|");
  const matches = WC.MATCHES
    .filter((m) => m.ven === venue && m.city === city)
    .sort((a, b) => a.iso.localeCompare(b.iso));
  return (
    <section className="today-group">
      <h2 className="today-group__h">{venue} maçları</h2>
      <div className="list">
        {matches.map((mt) => (
          <MatchCard key={mt.id} mt={mt} now={now} favs={favs} toggleFav={toggleFav} onOpen={noop} onOpenTeam={onOpenTeam} />
        ))}
      </div>
    </section>
  );
}

function EmptyState({ onReset }) {
  return (
    <div className="empty">
      <div className="empty__icon" aria-hidden="true">
        <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" strokeWidth="1.5">
          <circle cx="11" cy="11" r="7" /><path d="M20 20l-3.5-3.5" />
        </svg>
      </div>
      <p className="empty__title">Maç bulunamadı</p>
      <p className="empty__hint">Seçili filtrelerle eşleşen maç yok. Filtreleri sıfırlayarak tekrar deneyin.</p>
      <button className="empty__btn" onClick={onReset}>Filtreleri temizle</button>
    </div>
  );
}

/* ---- oyuncu ilginç bilgileri (player-facts.js) ---- */
function playerFactId(team, no) {
  return team + "-" + no;
}

function getPlayerFact(team, no) {
  if (typeof WC_PLAYER_FACTS === "undefined" || !WC_PLAYER_FACTS.facts) return null;
  return WC_PLAYER_FACTS.facts[playerFactId(team, no)] || null;
}

function WhatsAppIcon({ size = 14 }) {
  return (
    <svg className="wa-promo__icon" viewBox="0 0 24 24" width={size} height={size} aria-hidden="true">
      <path fill="currentColor" d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.435 9.884-9.883 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" />
    </svg>
  );
}

function XShareIcon() {
  return (
    <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
      <path fill="currentColor" d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
    </svg>
  );
}

function FactShareLinks({ share }) {
  if (!share) return null;
  const onWaClick = async (e) => {
    if (await shareFactWithImage(share)) e.preventDefault();
  };
  return (
    <span className="squad-pl__fact-share">
      <a
        className="squad-pl__fact-share-btn squad-pl__fact-share-btn--wa"
        href={share.waUrl}
        target="_blank"
        rel="noopener noreferrer"
        aria-label="WhatsApp ile paylaş"
        onClick={onWaClick}
      >
        <WhatsAppIcon />
        <span>WhatsApp</span>
      </a>
      <a
        className="squad-pl__fact-share-btn squad-pl__fact-share-btn--x"
        href={share.xUrl}
        target="_blank"
        rel="noopener noreferrer"
        aria-label="X ile paylaş"
      >
        <XShareIcon />
        <span>X</span>
      </a>
    </span>
  );
}

function PlayerFactLine({ team, no, teamName, playerName }) {
  const fact = getPlayerFact(team, no);
  if (!fact?.text) return null;
  const share = buildFactShare(playerName, teamName, fact.text, team, fact.image, playerFactId(team, no));
  return (
    <p className="squad-pl__fact">
      <span className="squad-pl__fact-txt">{fact.text}</span>
      <span className="squad-pl__fact-actions">
        <FactShareLinks share={share} />
        {fact.source && (
          <a className="squad-pl__fact-src" href={fact.source} target="_blank" rel="noopener noreferrer">
            Kaynak
          </a>
        )}
      </span>
    </p>
  );
}

function FactImageLightbox({ src, caption, share, onClose }) {
  const closeRef = React.useRef(null);
  useEffect(() => {
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    document.body.style.overflow = "hidden";
    closeRef.current?.focus();
    return () => {
      window.removeEventListener("keydown", h);
      document.body.style.overflow = "";
    };
  }, [onClose]);

  return (
    <div className="factimg-ovl" onClick={onClose} role="presentation">
      <div
        className="factimg"
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-label={caption || "Oyuncu bilgisi görseli"}
      >
        <button ref={closeRef} type="button" className="factimg__x" onClick={onClose} aria-label="Kapat">
          <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
            <path fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" d="M6 6l12 12M18 6L6 18" />
          </svg>
        </button>
        <img className="factimg__img" src={src} alt="" decoding="async" />
        {caption && (
          <div className="factimg__foot">
            <p className="factimg__cap">{caption}</p>
            <FactShareLinks share={share} />
          </div>
        )}
      </div>
    </div>
  );
}

/* ---- takım kadrosu ---- */
function TeamDetail({ code, now, favs, toggleFav, onClose, onOpenTeam, inline }) {
  const [factImage, setFactImage] = useState(null);
  const closeRef = React.useRef(null);
  const noop = () => {};
  useEffect(() => {
    if (inline || !onClose) return;
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    document.body.style.overflow = "hidden";
    closeRef.current?.focus();
    return () => { window.removeEventListener("keydown", h); document.body.style.overflow = ""; };
  }, [onClose, inline]);

  const teamMatches = useMemo(
    () => (code ? WC.MATCHES.filter((m) => m.h === code || m.a === code) : []).sort((a, b) => a.iso.localeCompare(b.iso)),
    [code]
  );
  const openTeam = onOpenTeam || noop;

  if (!code) return null;
  const t = WC.TEAMS[code];
  const grp = teamGroup(code);
  const squad = typeof WC_SQUADS !== "undefined" ? WC_SQUADS.byTeam[code] : null;
  const factCount = squad
    ? squad.players.filter((p) => getPlayerFact(code, p.no)).length
    : 0;

  const body = (
    <div className={inline ? "page-sheet" : "sheet"} onClick={inline ? undefined : (e) => e.stopPropagation()} role={inline ? undefined : "dialog"} aria-modal={inline ? undefined : "true"} aria-labelledby="team-sheet-title">
        {!inline && (
        <header className="sheet__head">
          <span className="sheet__head-sp" aria-hidden="true" />
          <div className="sheet__grab" aria-hidden="true" />
          <button ref={closeRef} type="button" className="sheet__x" onClick={onClose} aria-label="Kapat">
            <svg className="sheet__x-ico" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
              <path fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" d="M6 6l12 12M18 6L6 18" />
            </svg>
          </button>
        </header>
        )}
        <div className="sheet__scroll">
          <header className="squad-hd">
            <Badge code={code} fav={favs.includes(code)} size="sheet" />
            <div className="squad-hd__info">
              <h2 className="squad-hd__name" id="team-sheet-title">{t.ad}</h2>
              <p className="squad-hd__meta">
                {grp && <>Grup {grp} · </>}
                {squad ? (squad.kind === "final" ? "Resmî kadro" : "Aday kadro") : "Kadro"}
                {squad?.announced && <> · {squad.announced}</>}
                {squad?.players && <> · {squad.players.length} oyuncu</>}
              </p>
              {typeof WC_SQUADS !== "undefined" && (
                <p className="squad-hd__src">
                  <a href={WC_SQUADS.SOURCE.url} target="_blank" rel="noopener noreferrer">{WC_SQUADS.SOURCE.label}</a>
                </p>
              )}
            </div>
          </header>
          <button type="button" aria-pressed={favs.includes(code)} className={"tagfav" + (favs.includes(code) ? " on" : "")} onClick={() => toggleFav(code)}>
            ★ Favori takım
          </button>
          {grp && (
            <section className="team-block team-block--grp" aria-labelledby={"team-grp-" + code}>
              <h3 className="sheet__gt" id={"team-grp-" + code}>Grup {grp} — Puan durumu</h3>
              <MiniTable group={grp} now={now} favs={favs} onOpenTeam={openTeam} />
            </section>
          )}
          {teamMatches.length > 0 && (
            <section className="team-block team-block--matches" aria-labelledby={"team-matches-" + code}>
              <h3 className="sheet__gt" id={"team-matches-" + code}>Tüm maçlar ({teamMatches.length})</h3>
              <div className="list">
                {teamMatches.map((mt) => (
                  <MatchCard key={mt.id} mt={mt} now={now} favs={favs} toggleFav={toggleFav} onOpen={noop} onOpenTeam={openTeam} />
                ))}
              </div>
            </section>
          )}
          {!squad ? (
            <p className="squad-empty">Bu takım için kadro verisi henüz yüklenmedi.</p>
          ) : (
            WC_SQUADS.POS_ORDER.map((pos) => {
              const list = WC_SQUADS.groupByPos(squad.players)[pos];
              if (!list.length) return null;
              return (
                <section className="squad-sec" key={pos} aria-labelledby={"squad-pos-" + code + "-" + pos}>
                  <div className="squad-sec__h">
                    <h3 id={"squad-pos-" + code + "-" + pos}>{WC_SQUADS.POS_LABEL[pos]}</h3>
                    <span className="squad-sec__n">{list.length}</span>
                  </div>
                  <ul className="squad-list">
                    {list.map((p) => {
                      const fact = getPlayerFact(code, p.no);
                      return (
                      <li key={p.no} className="squad-pl">
                        <span className="squad-pl__no">{p.no}</span>
                        <span className="squad-pl__name">
                          {fact?.image && (
                            <button
                              type="button"
                              className="squad-pl__fact-thumb-btn"
                              onClick={() => setFactImage({
                                src: fact.image,
                                caption: fact.text,
                                share: buildFactShare(p.name, t.ad, fact.text, code, fact.image, playerFactId(code, p.no)),
                              })}
                              aria-label={p.name + " — bilgi görselini büyüt"}
                            >
                              <img
                                className="squad-pl__fact-thumb"
                                src={fact.image}
                                alt=""
                                width={32}
                                height={32}
                                loading="lazy"
                                decoding="async"
                              />
                            </button>
                          )}
                          <span className="squad-pl__name-txt">{p.name}</span>
                          {p.captain && <span className="squad-pl__cap" title="Kaptan">K</span>}
                        </span>
                        <span className="squad-pl__stat">{p.caps} maç · {p.goals} gol</span>
                        <span className="squad-pl__club">{p.club}</span>
                        <PlayerFactLine team={code} no={p.no} teamName={t.ad} playerName={p.name} />
                      </li>
                      );
                    })}
                  </ul>
                </section>
              );
            })
          )}
          {factCount > 0 && (
            <p className="squad-facts-note">
              {factCount} oyuncu için kısa bilgi gösteriliyor. Kaynaklar yerel dilde web araması; gösterim amaçlı özetlerdir.
            </p>
          )}
        </div>
      </div>
  );

  if (inline) {
    return (
      <>
        {body}
        {factImage && (
          <FactImageLightbox
            src={factImage.src}
            caption={factImage.caption}
            share={factImage.share}
            onClose={() => setFactImage(null)}
          />
        )}
      </>
    );
  }
  return (
    <>
      <div className="ovl" onClick={onClose} role="presentation">
        {body}
      </div>
      {factImage && (
        <FactImageLightbox
          src={factImage.src}
          caption={factImage.caption}
          share={factImage.share}
          onClose={() => setFactImage(null)}
        />
      )}
    </>
  );
}

/* ---- maç tartışması ---- */
function getVoterId() {
  try {
    let id = localStorage.getItem("wc_voter");
    if (!id) {
      id = typeof crypto !== "undefined" && crypto.randomUUID
        ? crypto.randomUUID()
        : "v-" + Date.now() + "-" + Math.random().toString(36).slice(2, 10);
      localStorage.setItem("wc_voter", id);
    }
    return id;
  } catch (e) {
    return "anon-" + Date.now();
  }
}

function discussTime(ts) {
  const d = new Date(ts);
  const diff = Date.now() - ts;
  if (diff < 60000) return "Az önce";
  if (diff < 3600000) return Math.floor(diff / 60000) + " dk önce";
  if (diff < 86400000) return Math.floor(diff / 3600000) + " sa önce";
  return d.toLocaleString("tr-TR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit", timeZone: "Europe/Istanbul" });
}

function MatchDiscuss({ matchId }) {
  const voterId = useMemo(() => getVoterId(), []);
  const [author, setAuthor] = usePersist("wc_discuss_author", "");
  const [comments, setComments] = useState([]);
  const [loading, setLoading] = useState(true);
  const [unavailable, setUnavailable] = useState(false);
  const [errMsg, setErrMsg] = useState("");
  const [text, setText] = useState("");
  const [submitting, setSubmitting] = useState(false);

  const load = useCallback(() => {
    setLoading(true);
    setErrMsg("");
    const q = "/api/discuss?matchId=" + encodeURIComponent(matchId) + "&voterId=" + encodeURIComponent(voterId);
    fetch(q)
      .then((r) => r.json().then((data) => ({ ok: r.ok, data })))
      .then(({ ok, data }) => {
        if (!ok && data.error === "discuss_unavailable") {
          setUnavailable(true);
          setComments([]);
        } else {
          setUnavailable(false);
          setComments(data.comments || []);
        }
        setLoading(false);
      })
      .catch(() => {
        setUnavailable(true);
        setLoading(false);
      });
  }, [matchId, voterId]);

  useEffect(() => { load(); }, [load]);

  const submit = (e) => {
    e.preventDefault();
    const body = text.trim();
    const name = author.trim();
    if (!name || body.length < 2) {
      setErrMsg("Takma ad ve en az 2 karakterlik yorum gerekli.");
      return;
    }
    setSubmitting(true);
    setErrMsg("");
    fetch("/api/discuss", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ action: "comment", matchId, voterId, author: name, body }),
    })
      .then((r) => r.json().then((data) => ({ ok: r.ok, data })))
      .then(({ ok, data }) => {
        if (!ok) {
          setErrMsg(data.message || "Yorum gönderilemedi.");
          return;
        }
        if (data.comment) setComments((c) => [data.comment, ...c]);
        setText("");
      })
      .catch(() => setErrMsg("Bağlantı hatası."))
      .finally(() => setSubmitting(false));
  };

  const vote = (commentId, voteVal) => {
    fetch("/api/discuss", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ action: "vote", commentId, voterId, vote: voteVal }),
    })
      .then((r) => r.json().then((data) => ({ ok: r.ok, data })))
      .then(({ ok, data }) => {
        if (!ok) return;
        setComments((list) => list.map((c) =>
          c.id === data.commentId
            ? { ...c, likes: data.likes, dislikes: data.dislikes, myVote: data.myVote }
            : c
        ));
      })
      .catch(() => {});
  };

  return (
    <section className="discuss" aria-labelledby={"discuss-h-" + matchId}>
      <h4 className="discuss__h" id={"discuss-h-" + matchId}>Maç tartışması</h4>
      <p className="discuss__sub">Fikrini paylaş; yorumlar herkese açıktır.</p>

      {!unavailable && (
        <form className="discuss__form" onSubmit={submit}>
          <label className="discuss__lbl">
            <span className="discuss__lbl-t">Takma ad</span>
            <input
              type="text"
              className="discuss__in"
              value={author}
              onChange={(e) => setAuthor(e.target.value)}
              maxLength={40}
              placeholder="Örn. Ayşe"
              autoComplete="nickname"
            />
          </label>
          <label className="discuss__lbl">
            <span className="discuss__lbl-t">Yorumun</span>
            <textarea
              className="discuss__ta"
              value={text}
              onChange={(e) => setText(e.target.value)}
              maxLength={600}
              rows={3}
              placeholder="Maç öncesi tahmin, kadro, taktik…"
            />
          </label>
          {errMsg && <p className="discuss__err" role="alert">{errMsg}</p>}
          <button type="submit" className="discuss__send" disabled={submitting}>
            {submitting ? "Gönderiliyor…" : "Yorumu paylaş"}
          </button>
        </form>
      )}

      {unavailable && (
        <p className="discuss__off">
          Tartışma sunucusu henüz etkin değil. Cloudflare D1 kurulumu sonrası yorumlar burada görünür.
        </p>
      )}

      <div className="discuss__list" aria-live="polite">
        {loading && <p className="discuss__muted">Yorumlar yükleniyor…</p>}
        {!loading && !unavailable && comments.length === 0 && (
          <p className="discuss__muted">Henüz yorum yok — ilk sen yaz.</p>
        )}
        {!loading && comments.map((c) => (
          <article key={c.id} className="discuss__c">
            <header className="discuss__c-h">
              <strong className="discuss__c-author">{c.author}</strong>
              <time className="discuss__c-time" dateTime={new Date(c.createdAt).toISOString()}>{discussTime(c.createdAt)}</time>
            </header>
            <p className="discuss__c-body">{c.body}</p>
            <div className="discuss__votes" role="group" aria-label="Yorum oyları">
              <button
                type="button"
                className={"discuss__vote discuss__vote--up" + (c.myVote === 1 ? " discuss__vote--on" : "")}
                aria-pressed={c.myVote === 1}
                onClick={() => vote(c.id, 1)}
              >
                <span aria-hidden="true">▲</span> {c.likes}
              </button>
              <button
                type="button"
                className={"discuss__vote discuss__vote--down" + (c.myVote === -1 ? " discuss__vote--on" : "")}
                aria-pressed={c.myVote === -1}
                onClick={() => vote(c.id, -1)}
              >
                <span aria-hidden="true">▼</span> {c.dislikes}
              </button>
            </div>
          </article>
        ))}
      </div>
    </section>
  );
}

/* ---- match detail sheet ---- */
function Detail({ mt, now, favs, toggleFav, onClose, onOpenTeam, inline, showBlogLink }) {
  const closeRef = React.useRef(null);
  useEffect(() => {
    if (inline || !onClose) return;
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    document.body.style.overflow = "hidden";
    closeRef.current?.focus();
    return () => { window.removeEventListener("keydown", h); document.body.style.overflow = ""; };
  }, [onClose, inline]);

  if (!mt) return null;
  const st = statusOf(mt, now);
  const sc = effectiveScore(mt);
  const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
  const blogHref = blogMatchUrl(mt);
  const body = (
      <div className={inline ? "page-sheet" : "sheet"} onClick={inline ? undefined : (e) => e.stopPropagation()} role={inline ? undefined : "dialog"} aria-modal={inline ? undefined : "true"} aria-labelledby="sheet-title">
        {!inline && (
        <header className="sheet__head">
          <span className="sheet__head-sp" aria-hidden="true" />
          <div className="sheet__grab" aria-hidden="true" />
          <button ref={closeRef} type="button" className="sheet__x" onClick={onClose} aria-label="Kapat">
            <svg className="sheet__x-ico" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
              <path fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" d="M6 6l12 12M18 6L6 18" />
            </svg>
          </button>
        </header>
        )}
        <div className="sheet__scroll">
        {showBlogLink && blogHref && (
          <p className="blog-banner"><a href={blogHref}>{blogDisplayName(mt)}</a></p>
        )}
        <div className="sheet__top">
          <span className="meta__grp">Grup {mt.g} · {mt.md}. maç günü</span>
          <h2 className="sheet__date" id="sheet-title">{dayLong(mt.iso)}</h2>
          <div className="sheet__score">
            <div className="sheet__team">
              <Badge code={mt.h} fav={favs.includes(mt.h)} size="sheet" />
              <TeamNameBtn code={mt.h} onOpenTeam={onOpenTeam} />
            </div>
            <div className="sheet__mid">
              {st !== "sched" && sc
                ? <span className="sheet__sc">{sc[0]} – {sc[1]}</span>
                : <span className="sheet__ko">{hhmm(mt.iso)}</span>}
              <StatusPill st={st} mt={mt} now={now} />
            </div>
            <div className="sheet__team sheet__team--r">
              <TeamNameBtn code={mt.a} onOpenTeam={onOpenTeam} />
              <Badge code={mt.a} fav={favs.includes(mt.a)} size="sheet" />
            </div>
          </div>
        </div>
        <dl className="info">
          <div><dt>Başlama (TSİ)</dt><dd>{hhmm(mt.iso)} — {dayLong(mt.iso)}</dd></div>
          <div><dt>Stadyum</dt><dd>{mt.ven}</dd></div>
          <div><dt>Şehir</dt><dd>{mt.city}, {mt.country}</dd></div>
          <div><dt>Yayın</dt><dd><ChannelBadge channel={mt.ch} /></dd></div>
        </dl>
        {st === "sched" && (
          <div className="sheet__cal">
            <AddToCalendar matches={mt} now={now} />
            <p className="sheet__cal-hint">{calendarHint(calendarPlatform())}</p>
          </div>
        )}
        <div className="info__fav">
          <span>Favori takip:</span>
          <button type="button" aria-pressed={favs.includes(mt.h)} className={"tagfav" + (favs.includes(mt.h) ? " on" : "")} onClick={() => toggleFav(mt.h)}>★ {H.ad}</button>
          <button type="button" aria-pressed={favs.includes(mt.a)} className={"tagfav" + (favs.includes(mt.a) ? " on" : "")} onClick={() => toggleFav(mt.a)}>★ {A.ad}</button>
        </div>
        <h4 className="sheet__gt">Grup {mt.g} — Puan durumu</h4>
        <MiniTable group={mt.g} now={now} favs={favs} onOpenTeam={onOpenTeam} />
        <MatchDiscuss matchId={mt.id} />
        </div>
      </div>
  );

  if (inline) return body;
  return (
    <div className="ovl" onClick={onClose} role="presentation">
      {body}
    </div>
  );
}

function PageLayout({ banner, children, backHref = "/", backLabel = "← Tüm maçlar", extraNav = null }) {
  return (
    <div className="page-layout">
      <nav className="page-nav" aria-label="Sayfa">
        <a className="page-back" href={backHref}>{backLabel}</a>
        {extraNav && (
          <React.Fragment>
            <span className="page-nav__sep" aria-hidden="true">·</span>
            {extraNav}
          </React.Fragment>
        )}
      </nav>
      {banner}
      {children}
    </div>
  );
}

function BlogPost({ mt, favs }) {
  const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
  const macHref = matchUrl(mt);
  const hHref = teamUrl(mt.h);
  const aHref = teamUrl(mt.a);
  const when = dayShort(mt.iso) + " " + hhmm(mt.iso) + " TSİ";

  return (
    <article className="blog-post">
      <header className="blog-post__hero">
        <p className="blog-post__kicker">Grup {mt.g} · {mt.md}. maç günü</p>
        <h1 className="blog-post__title">{blogDisplayName(mt)}</h1>
        <p className="blog-post__lead">
          {when} tarihinde <strong>{mt.ven}</strong> ({mt.city}, {mt.country}) stadyumunda oynanacak Grup {mt.g} maçı.
          Kick-off <strong>Türkiye saati (TSİ)</strong> ile {hhmm(mt.iso)}.
        </p>
        <div className="blog-post__teams">
          <div className="blog-post__team">
            <Badge code={mt.h} fav={favs.includes(mt.h)} size="sheet" />
            {hHref
              ? <a className="blog-post__team-name" href={hHref}>{H.ad}</a>
              : <span className="blog-post__team-name">{H.ad}</span>}
          </div>
          <span className="blog-post__vs" aria-hidden="true">–</span>
          <div className="blog-post__team">
            <Badge code={mt.a} fav={favs.includes(mt.a)} size="sheet" />
            {aHref
              ? <a className="blog-post__team-name" href={aHref}>{A.ad}</a>
              : <span className="blog-post__team-name">{A.ad}</span>}
          </div>
        </div>
      </header>

      {macHref && (
        <aside className="blog-post__cta">
          Canlı skor, takvime ekleme ve tartışma için{" "}
          <a href={macHref}>maç detay sayfasına</a> gidin.
        </aside>
      )}

      <div className="blog-post__body">
        <section>
          <h2>Maç bilgileri</h2>
          <dl className="blog-post__facts">
            <div><dt>Tarih</dt><dd>{dayLong(mt.iso)}</dd></div>
            <div><dt>Saat (TSİ)</dt><dd>{hhmm(mt.iso)}</dd></div>
            <div><dt>Stadyum</dt><dd>{mt.ven}</dd></div>
            <div><dt>Şehir</dt><dd>{mt.city}, {mt.country}</dd></div>
            <div><dt>Yayın</dt><dd>{mt.ch || "TRT (gösterim amaçlı)"}</dd></div>
            <div><dt>Maç günü</dt><dd>Grup {mt.g}, {mt.md}. maç günü</dd></div>
          </dl>
        </section>
        <section>
          <h2>Takımlar</h2>
          <p className="blog-post__prose">
            Bu karşılaşmada{" "}
            {hHref ? <a href={hHref}>{H.ad}</a> : H.ad}{" "}
            ile{" "}
            {aHref ? <a href={aHref}>{A.ad}</a> : A.ad}{" "}
            karşı karşıya geliyor. Kadrolar ve oyuncu notları için takım sayfalarına göz atın.
          </p>
        </section>
        <section>
          <h2>Grup {mt.g} bağlamı</h2>
          <p className="blog-post__prose">
            Grup {mt.g} puan durumu ve diğer maçlar için{" "}
            <a href="/#main">ana program</a> sayfasındaki Gruplar sekmesini kullanabilirsiniz.
          </p>
        </section>
      </div>

      <footer className="blog-post__note">
        Bu yazı fikstür verisinden otomatik üretilmiştir. Skor ve yayın bilgisi maç günü güncellenebilir.
      </footer>
    </article>
  );
}

function PageHeader({ title }) {
  return (
    <header className="hd">
      <div className="hd__wrap">
        <div className="hd__brand">
          <a className="hd__logo-btn" href="/" aria-label="Ana sayfa">
            <img className="hd__logo" src="/wc26-logo.jpg" alt="" width="34" height="52" decoding="async" />
          </a>
          <span className="hd__brand-sep" aria-hidden="true" />
          <div>
            <h1 className="hd__title">DÜNYA KUPASI 2026</h1>
            <div className="hd__sub">{title}</div>
          </div>
        </div>
        <HeaderSearch />
      </div>
    </header>
  );
}

function useFavState() {
  const [favs, setFavs] = usePersist("wc_favs", ["TUR"]);
  const toggleFav = useCallback((code) => {
    setFavs((f) => f.includes(code) ? f.filter((x) => x !== code) : [...f, code]);
  }, [setFavs]);
  return { favs, toggleFav };
}

function StandalonePage({ children, title, mainClass = "" }) {
  return (
    <div className="app dens-rahat app--page" style={{ "--accent": ACCENT }}>
      <PageHeader title={title} />
      <SiteAdPromo />
      <main id="main" className={"main main--page" + (mainClass ? " " + mainClass : "")}>
        {children}
        <SiteXPromo />
        <SiteFooter />
      </main>
    </div>
  );
}

function DeepLinkApp() {
  const [tick, setTick] = useState(0);
  const bump = useCallback(() => setTick((x) => x + 1), []);
  useScoreFeed(bump);
  useEffect(() => {
    const id = setInterval(() => setTick((x) => x + 1), 30000);
    return () => clearInterval(id);
  }, []);
  const now = useMemo(() => new Date(), [tick]);
  const { favs, toggleFav } = useFavState();
  const page = window.WC_PAGE || {};
  const noop = () => {};

  if (page.type === "match") {
    const mt = WC.MATCHES.find((m) => m.id === page.matchId);
    if (!mt) return (
      <StandalonePage title="Maç bulunamadı">
        <PageLayout><p className="page-message">Maç bulunamadı. <a href="/">Ana sayfa</a></p></PageLayout>
      </StandalonePage>
    );
    const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
    return (
      <StandalonePage title={H.ad + " – " + A.ad}>
        <PageLayout>
          <Detail mt={mt} now={now} favs={favs} toggleFav={toggleFav} onClose={noop} onOpenTeam={noop} inline showBlogLink />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "blog-match") {
    const mt = WC.MATCHES.find((m) => m.id === page.matchId);
    if (!mt) return (
      <StandalonePage title="Maç bulunamadı">
        <PageLayout><p className="page-message">Maç bulunamadı. <a href="/">Ana sayfa</a></p></PageLayout>
      </StandalonePage>
    );
    const H = WC.TEAMS[mt.h], A = WC.TEAMS[mt.a];
    const macHref = matchUrl(mt);
    return (
      <StandalonePage title={H.ad + " – " + A.ad}>
        <PageLayout
          backLabel="← Ana program"
          extraNav={macHref ? <a className="page-nav__link" href={macHref}>Maç detayı</a> : null}
        >
          <BlogPost mt={mt} favs={favs} />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "team") {
    return (
      <StandalonePage title={WC.TEAMS[page.teamCode]?.ad || "Takım"}>
        <PageLayout>
          <TeamDetail code={page.teamCode} now={now} favs={favs} toggleFav={toggleFav} onClose={noop} onOpenTeam={noop} inline />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "stadium") {
    const [venueName] = String(page.venueKey || "").split("|");
    return (
      <StandalonePage title={venueName || "Stadyum"}>
        <PageLayout backLabel="← Ana program" extraNav={<a className="page-nav__link" href="/turnuva-agaci/">Turnuva ağacı</a>}>
          <VenueMatchesView venueKey={page.venueKey} now={now} favs={favs} toggleFav={toggleFav} onOpenTeam={noop} />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "turkey") {
    return (
      <StandalonePage title="Türkiye'nin 2026 Dünya Kupası maçları">
        <PageLayout backLabel="← Ana program" extraNav={<a className="page-nav__link" href={teamUrl("TUR") || "/"}>Türkiye kadrosu</a>}>
          <TurkeyMatchesView now={now} favs={favs} toggleFav={toggleFav} onOpenTeam={noop} />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "today") {
    return (
      <StandalonePage title="Bugün ve yarın oynanacak Dünya Kupası maçları">
        <PageLayout backLabel="← Ana program" extraNav={<a className="page-nav__link" href="/#main">Tüm program</a>}>
          <TodayMatchesView now={now} favs={favs} toggleFav={toggleFav} onOpenTeam={noop} />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "group") {
    const g = page.group;
    return (
      <StandalonePage title={"Grup " + g + " puan durumu"}>
        <PageLayout backLabel="← Ana program" extraNav={<a className="page-nav__link" href="/#main">Tüm gruplar</a>}>
          <section className="grpcard grpcard--page">
            <MiniTable group={g} now={now} favs={favs} onOpenTeam={noop} />
          </section>
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "bracket") {
    return (
      <StandalonePage title="Turnuva ağacı" mainClass="main--agac">
        <PageLayout backLabel="← Ana program" extraNav={<a className="page-nav__link" href="/#main">Tüm program</a>}>
          <BracketView now={now} scoreTick={tick} />
        </PageLayout>
      </StandalonePage>
    );
  }

  if (page.type === "static") {
    return (
      <div className="app--static-hd" style={{ "--accent": ACCENT }}>
        <PageHeader title={page.headerTitle || "Blog & rehberler"} />
      </div>
    );
  }

  return <App />;
}

/* ---- main app ---- */
const ALL_DATES = [...new Set(WC.MATCHES.map((m) => dateKey(m.iso)))].sort();

function App() {
  const [tick, setTick] = useState(0);
  const bump = useCallback(() => setTick((x) => x + 1), []);
  useScoreFeed(bump);

  useEffect(() => {
    const id = setInterval(() => setTick((x) => x + 1), 30000);
    return () => clearInterval(id);
  }, []);

  const now = useMemo(() => new Date(), [tick]);

  // Istanbul local date (UTC+3) for "today" highlight
  const todayKey = useMemo(() => {
    const ist = new Date(now.getTime() + 3 * 3600000);
    const y  = ist.getUTCFullYear();
    const mo = String(ist.getUTCMonth() + 1).padStart(2, "0");
    const da = String(ist.getUTCDate()).padStart(2, "0");
    return `${y}-${mo}-${da}`;
  }, [now]);

  const [view,    setView]    = usePersist("wc_view",    "program");
  const [dateF,   setDateF]   = usePersist("wc_date",    ALL_DATES.includes(todayKey) ? todayKey : "all");
  const [group,   setGroup]   = usePersist("wc_group",   "all");
  const [status,  setStatus]  = usePersist("wc_status",  "all");
  const [favOnly, setFavOnly] = usePersist("wc_favonly", false);
  const [favs,    setFavs]    = usePersist("wc_favs",    ["TUR"]);
  const [detail,  setDetail]  = useState(null);
  const [teamDetail, setTeamDetail] = useState(null);

  const openTeam = useCallback((code) => {
    setDetail(null);
    setTeamDetail(code);
  }, []);

  const openMatch = useCallback((mt) => {
    setTeamDetail(null);
    setDetail(mt);
  }, []);

  const toggleFav = useCallback((code) => {
    setFavs((f) => f.includes(code) ? f.filter((x) => x !== code) : [...f, code]);
  }, [setFavs]);

  const resetFilters = useCallback(() => {
    setDateF(ALL_DATES.includes(todayKey) ? todayKey : "all");
    setGroup("all");
    setStatus("all");
    setFavOnly(false);
  }, [setDateF, setGroup, setStatus, setFavOnly, todayKey]);

  const defaultDate = ALL_DATES.includes(todayKey) ? todayKey : "all";
  const hasActiveFilters = group !== "all" || status !== "all" || favOnly || dateF !== defaultDate;

  const filtered = useMemo(() => {
    return WC.MATCHES.filter((m) => {
      if (dateF  !== "all" && dateKey(m.iso) !== dateF)      return false;
      if (group  !== "all" && m.g !== group)                  return false;
      if (favOnly && !favs.includes(m.h) && !favs.includes(m.a)) return false;
      if (status !== "all" && statusOf(m, now) !== status)   return false;
      return true;
    }).sort((a, b) => a.iso.localeCompare(b.iso));
  }, [dateF, group, favOnly, favs, status, now]);

  const grouped = useMemo(() => {
    const g = {};
    filtered.forEach((m) => { const k = dateKey(m.iso); (g[k] = g[k] || []).push(m); });
    return Object.keys(g).sort().map((k) => [k, g[k]]);
  }, [filtered]);

  const nextUpId = useMemo(() => {
    let id = null;
    let best = Infinity;
    filtered.forEach((m) => {
      if (statusOf(m, now) !== "sched") return;
      const t = new Date(m.iso).getTime();
      if (t < best) { best = t; id = m.id; }
    });
    return id;
  }, [filtered, now]);

  const liveCount = useMemo(() =>
    WC.MATCHES.filter((m) => statusOf(m, now) === "live").length, [now, tick]);

  useEffect(() => {
    if (view !== "program" || !nextUpId) return;
    const el = document.querySelector(".match--next");
    el?.scrollIntoView({ block: "nearest", behavior: "smooth" });
  }, [view, nextUpId]);

  const goProgram = useCallback(() => {
    setView("program");
    setDetail(null);
    setTeamDetail(null);
    document.getElementById("main")?.scrollIntoView({ behavior: "smooth", block: "start" });
  }, [setView]);

  return (
    <div className="app dens-rahat" style={{ "--accent": ACCENT }}>
      <a className="skip" href="#main">İçeriğe atla</a>
      <header className="hd">
        <div className="hd__wrap">
          <div className="hd__brand">
            <button type="button" className="hd__logo-btn" onClick={goProgram} aria-label="Program sayfasına git">
              <img className="hd__logo" src="wc26-logo.jpg" alt="" width="34" height="52" decoding="async" />
            </button>
            <span className="hd__brand-sep" aria-hidden="true" />
            <div>
              <h1 className="hd__title">DÜNYA KUPASI 2026</h1>
              <div className="hd__sub">
                {view === "program" && "Grup aşaması · Türkiye saati (TSİ / GMT+3)"}
                {view === "gruplar" && "12 grup · Puan durumu"}
                {view === "agac" && "Eleme turu · Fikstür"}
              </div>
            </div>
          </div>
          <HeaderSearch />
          <div className="hd__right">
            {liveCount > 0 && <span className="hd__live"><span className="dot" />{liveCount} canlı</span>}
            <div className="seg" role="group" aria-label="Görünüm">
              <button aria-pressed={view === "program"} className={"seg__b" + (view === "program"  ? " seg__b--on" : "")} onClick={() => setView("program")}>Program</button>
              <button aria-pressed={view === "gruplar"} className={"seg__b" + (view === "gruplar" ? " seg__b--on" : "")} onClick={() => setView("gruplar")}>Gruplar</button>
              <button aria-pressed={view === "agac"} className={"seg__b" + (view === "agac" ? " seg__b--on" : "")} onClick={() => setView("agac")}>Ağaç</button>
            </div>
          </div>
        </div>
      </header>

      <SiteAdPromo />

      <main className={"main" + (view === "agac" ? " main--agac" : "")} id="main">
        {view === "program" ? (
          <React.Fragment>
            <DateStrip dates={ALL_DATES} value={dateF} onChange={setDateF} todayKey={todayKey} now={now} />
            <FilterBar group={group} setGroup={setGroup} status={status} setStatus={setStatus}
              favOnly={favOnly} setFavOnly={setFavOnly} favCount={favs.length}
              hasFilters={hasActiveFilters} onReset={resetFilters} matchCount={filtered.length} />
            {grouped.length === 0 && <EmptyState onReset={resetFilters} />}
            {grouped.map(([dk, list]) => (
              <section className="daygrp" key={dk}>
                {dateF === "all" && (
                  <h2 className="dayhd">
                    {dayLong(dk + "T00:00:00+03:00")}
                    {dk === todayKey && <a className="dayhd__today" href="/bugun/">Bugün</a>}
                    <AddToCalendar matches={list} compact now={now} />
                  </h2>
                )}
                {dateF !== "all" && list.some((m) => statusOf(m, now) === "sched") && (
                  <div className="daycal">
                    <AddToCalendar matches={list} now={now} />
                  </div>
                )}
                <div className="list">
                  {list.map((m) => (
                    <MatchCard key={m.id} mt={m} now={now} favs={favs} toggleFav={toggleFav} onOpen={openMatch} onOpenTeam={openTeam} nextUp={m.id === nextUpId} />
                  ))}
                </div>
              </section>
            ))}
          </React.Fragment>
        ) : view === "gruplar" ? (
          <GroupsView now={now} favs={favs} onOpenTeam={openTeam} />
        ) : (
          <BracketView now={now} scoreTick={tick} />
        )}
        <SiteXPromo />
        <SiteFooter />
      </main>

      {detail && <Detail mt={detail} now={now} favs={favs} toggleFav={toggleFav} onClose={() => setDetail(null)} onOpenTeam={openTeam} />}
      {teamDetail && <TeamDetail code={teamDetail} now={now} favs={favs} toggleFav={toggleFav} onClose={() => setTeamDetail(null)} onOpenTeam={openTeam} />}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(
  window.WC_PAGE ? <DeepLinkApp /> : <App />
);
