﻿/* components.jsx - shared UI for the WC2026 top page */
const { useEffect, useRef, useState } = React;

function useInView(once = true) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const check = () => {
      const rect = el.getBoundingClientRect();
      if (rect.top < window.innerHeight * 0.92 && rect.bottom > 0) {
        setVisible(true);
        if (once) window.removeEventListener("scroll", check);
      }
    };
    window.addEventListener("scroll", check, { passive: true });
    window.addEventListener("resize", check);
    check();
    return () => {
      window.removeEventListener("scroll", check);
      window.removeEventListener("resize", check);
    };
  }, [once]);
  return [ref, visible];
}

function Reveal({ as: Tag = "div", className = "", delay = 0, children, ...props }) {
  const [ref, visible] = useInView();
  return <Tag ref={ref} className={`reveal ${visible ? "is-visible" : ""} ${className}`} style={{ transitionDelay: `${delay}ms`, ...(props.style || {}) }} {...props}>{children}</Tag>;
}

function CountUp({ to, decimals = 0 }) {
  const [ref, visible] = useInView();
  const [value, setValue] = useState(to);
  useEffect(() => {
    if (!visible) return;
    let raf;
    const start = performance.now();
    const duration = 850;
    const tick = (now) => {
      const p = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setValue(to * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
      else setValue(to);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [visible, to]);
  return <span ref={ref}>{Number(value).toFixed(decimals)}</span>;
}

function SectionHead({ eyebrow, title, lead, center = false }) {
  return <div className={`section-head ${center ? "section-head--center" : ""}`}><p className="eyebrow">{eyebrow}</p><h2>{title}</h2>{lead && <p>{lead}</p>}</div>;
}

function RatingRow({ team }) {
  const width = `${Math.max(0, Math.min(100, team.rating))}%`;
  return <div className="rating-row"><span className="flag"><Flag team={team.key} width="34" height="23" /></span><div className="rating-row__name"><b>{team.name}</b><small>{team.verdict}</small></div><div className="rating-row__score"><CountUp to={team.rating} decimals={1} /></div><div className="rating-row__track"><span style={{ width, background: `linear-gradient(90deg, ${team.colors[0]}, ${team.colors[1]})` }} /></div></div>;
}

function PowerPanel({ compact = false }) {
  return <div className={`power-panel ${compact ? "power-panel--compact" : ""}`}><div className="panel-title"><span>GROUP F</span><b>Power Rating</b></div>{teams.map((team) => <RatingRow key={team.key} team={team} />)}<p className="panel-note">独自100点評価。未掲載の項目は0扱いしません。</p></div>;
}

function RadarScoreList({ axes, values, color, compact = false }) {
  return <ul className={`top-radar-scores ${compact ? "top-radar-scores--compact" : ""}`}>{axes.map((axis, i) => <li key={axis}><span><i style={{ background: color }} />{axis}</span><b>{Math.round(Number(values[i] || 0))}</b></li>)}</ul>;
}

function RadarScoreGroups({ teams }) {
  return <div className="top-radar-groups">{teams.map((team) => <section key={team.key} className="top-radar-group"><h3><i style={{ background: team.colors[0] }} />{team.name}</h3><RadarScoreList axes={AXES} values={team.radar} color={team.colors[0]} compact /></section>)}</div>;
}
const TOP_TEAM_URLS = {
  ned: "/worldcup2026/teams/netherlands/",
  jpn: "/worldcup2026/teams/japan/",
  swe: "/worldcup2026/teams/sweden/",
  tun: "/worldcup2026/teams/tunisia/"
};

function TeamCard({ team, compact = false }) {
  const displayName = compact ? `${team.name}代表` : team.name;
  return <article className={`team-card${compact ? " team-card--compact" : ""}`}><div className="team-card__bar" style={{ background: `linear-gradient(90deg, ${team.colors[0]}, ${team.colors[1]})` }} /><div className="team-card__body"><div className="team-card__head"><span className="flag flag--large"><Flag team={team.key} width="44" height="30" /></span><div><h3>{displayName}</h3><p>{team.en}</p></div><span className={`verdict verdict--${team.verdictClass}`}>{team.verdict}</span></div><div className={`team-card__rating${compact ? " team-card__rating--compact" : ""}`}><strong style={{ color: team.colors[0] }}>{compact ? team.rating.toFixed(1) : <CountUp to={team.rating} decimals={1} />}</strong>{compact ? <span className="team-card__rank">{team.worldRank}位／{team.tournamentTeams}チーム</span> : <><span>/100</span><em>#{team.rank}</em></>}</div><p>{team.summary}</p>{compact && <a className="team-card__link" href={TOP_TEAM_URLS[team.key] || "/worldcup2026/groups/group-f/"}>詳細ページへ{I.arrow}</a>}</div></article>;
}

function GroupRatingCompare({ title = "Group F 独自レーティング", lead = "4チームの総合Ratingと6軸評価を、同じ画面で比較できます。" }) {
  const series = teams.map((team) => ({ values: team.radar, color: team.colors[0], fill: .12 }));
  return <section className="section section--dark wc-section-dark rating-compare" id="groupf"><div className="wrap"><SectionHead eyebrow="Group F Power Rating" title={title} lead={lead} /><div className="group-layout group-layout--rating"><div className="team-grid team-grid--rating">{teams.map((team, i) => <Reveal key={team.key} delay={i * 70}><TeamCard team={team} compact /></Reveal>)}</div><Reveal delay={120}><div className="radar-panel radar-panel--compare wc-card-dark"><HexRadar axes={AXES} series={series} size={330} /><div className="radar-legend">{teams.map((team) => <span key={team.key}><i style={{ background: team.colors[0] }} />{team.name}</span>)}</div><RadarScoreGroups teams={teams} /><a className="btn btn--gold rating-compare__link" href="/worldcup2026/groups/group-f/">Group F詳細ページへ</a></div></Reveal></div></div></section>;
}

function TeamFileCard({ team }) {
  return <article className="team-file"><div className="team-file__main"><div className="team-card__head"><span className="flag flag--large"><Flag team={team.key} width="44" height="30" /></span><div><h3>{team.name}</h3><p>{team.en}</p></div><span className={`verdict verdict--${team.verdictClass}`}>{team.verdict}</span></div><p className="team-file__note">{team.note}</p><div className="sw-grid"><div><b>強み</b><ul>{team.strengths.map((s) => <li key={s}>{s}</li>)}</ul></div><div><b>確認点</b><ul>{team.risks.map((r) => <li key={r}>{r}</li>)}</ul></div></div></div><div className="team-file__radar"><HexRadar axes={AXES} series={[{ values: team.radar, color: team.colors[0], fill: .2 }]} size={230} /><RadarScoreList axes={AXES} values={team.radar} color={team.colors[0]} compact /></div></article>;
}

function RatingBreakdownCard({ item }) {
  return <article className="break-card"><span className="break-card__num" style={{ color: item.color }}>{item.points}</span><span className="break-card__unit">pt</span><h3>{item.label}</h3><p>{item.desc}</p></article>;
}

function MatchScheduleCard() {
  return <div className="schedule-card"><div className="schedule-card__head"><div><b>日本代表の日程カード</b><span>{DATA_STATUS}</span></div><small>最終更新日：{LAST_UPDATED}</small></div>{matches.map((match) => <div className="match" key={match.id}><div className="match__date"><b>{match.date}</b><span>{match.round}</span></div><div className="match__teams"><span className="flag"><Flag team={match.homeKey} width="30" height="20" /></span><strong>{match.home}</strong><em>vs</em><strong>{match.away}</strong><span className="flag"><Flag team={match.awayKey} width="30" height="20" /></span></div><div className="match__meta"><span>{match.venue}</span><span>{match.broadcast}</span></div></div>)}</div>;
}

function GuideCard({ item }) {
  const content = <><img src={item.image} alt="" loading="lazy" /><span>{item.title}</span><b>{item.label}{!item.comingSoon && I.arrow}</b></>;
  if (item.comingSoon) return <article className="guide-card guide-card--soon" aria-label={`${item.title} Coming Soon`}>{content}</article>;
  return <a href={item.href} className="guide-card">{content}</a>;
}

function GoodsCard({ item }) {
  return <article className="goods-card"><div className="goods-card__icon">{I[item.icon] || I.device}</div><h3>{item.name}</h3><p>{item.desc}</p><a href={item.href || "/worldcup2026/goods/"}>確認する{I.arrow}</a></article>;
}

function ArticleCard({ item }) {
  return <a href={item.href} className="article-card"><div className="article-card__thumb"><span>{item.category}</span>{item.type === "video" && <i>{I.play}</i>}</div><div><small>{item.date}</small><h3>{item.title}</h3></div></a>;
}

function DisclaimerBox() {
  return <section className="disclaimer wc-card-dark" aria-label="非公式注意書き"><h2>{I.info} 非公式の観戦ガイドです</h2><p>本サイトは、FIFA・大会主催者・各国サッカー協会とは関係のない非公式の観戦ガイドです。掲載情報は公式発表および信頼できる公開情報をもとに作成し、随時更新します。独自レーティングや勝敗予想は当サイト独自の分析であり、結果を保証するものではありません。商品リンクにはアフィリエイトリンクを含む場合があります。</p></section>;
}

Object.assign(window, { Reveal, CountUp, SectionHead, PowerPanel, RadarScoreList, RadarScoreGroups, GroupRatingCompare, TeamCard, TeamFileCard, RatingBreakdownCard, MatchScheduleCard, GuideCard, GoodsCard, ArticleCard, DisclaimerBox });


