// Main App — composes Header, Hero, sections, MobileMenu, TweaksPanel.

// ── 운영 플래그 ────────────────────────────────────────────────────
// PROD_MODE: true이면 Tweaks 패널 미렌더, 시안 토글 UI 숨김.
// CANDIDATE_STATUS: 'pre_candidate' | 'official_candidate'.
//   officialRegistrationConfirmed=true가 될 때만 official로 전환.
//   (날짜 자동 전환 금지 — 정책 결정.)
// 두 값 모두 config.js의 window.__KDJ_CONFIG__로 주입 가능.
const KCFG = (typeof window !== "undefined" && window.__KDJ_CONFIG__) || {};
const PROD_MODE = KCFG.prodMode === true;
const CANDIDATE_STATUS = KCFG.candidateStatus || "pre_candidate";

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroVariant": "C",
  "showPhoto": true,
  "darkMode": false,
  "primaryTheme": "blue",
  "catchphrase": "통합도 착착, 교육도 착착"
}/*EDITMODE-END*/;

const THEMES = {
  navy: {
    "--c-primary": "#0B1F3A",
    "--c-primary-2": "#1D4ED8",
    "--c-accent": "#10B981",
  },
  blue: {
    "--c-primary": "#1D4ED8",
    "--c-primary-2": "#0EA5E9",
    "--c-accent": "#10B981",
  },
  mint: {
    "--c-primary": "#065F46",
    "--c-primary-2": "#10B981",
    "--c-accent": "#F59E0B",
  },
};

function EntryEffect({ active }) {
  if (!active) return null;
  return (
    <div className="entry-effect" aria-hidden="true">
      <span className="entry-effect-sweep" />
      <span className="entry-effect-line entry-effect-line-1" />
      <span className="entry-effect-line entry-effect-line-2" />
      <span className="entry-effect-line entry-effect-line-3" />
    </div>
  );
}

const REMOTE_SECTIONS = [
  { id: "top", label: "처음", n: "00", mobile: true },
  { id: "about", label: "소개", n: "01", mobile: false },
  { id: "vision", label: "비전", n: "02", mobile: true },
  { id: "achievements", label: "실천", n: "03", mobile: false },
  { id: "promises", label: "약속", n: "04", mobile: false },
  { id: "news", label: "소식", n: "05", mobile: true },
  { id: "support", label: "응원", n: "06", mobile: true },
  { id: "contact", label: "소통", n: "07", mobile: false },
];

function SectionRemote({ hidden }) {
  const [active, setActive] = React.useState("top");

  React.useEffect(() => {
    let raf = 0;
    const getSections = () => REMOTE_SECTIONS
      .map((item) => ({ ...item, el: document.getElementById(item.id) }))
      .filter((item) => item.el);

    const update = () => {
      raf = 0;
      const marker = window.scrollY + Math.min(window.innerHeight * 0.42, 360);
      const sections = getSections();
      let current = sections[0]?.id || "top";
      sections.forEach((item) => {
        if (item.el.offsetTop <= marker) current = item.id;
      });
      setActive((prev) => prev === current ? prev : current);
    };
    const requestUpdate = () => {
      if (raf) return;
      raf = window.requestAnimationFrame(update);
    };
    update();
    window.addEventListener("scroll", requestUpdate, { passive: true });
    window.addEventListener("resize", requestUpdate);
    return () => {
      window.removeEventListener("scroll", requestUpdate);
      window.removeEventListener("resize", requestUpdate);
      if (raf) window.cancelAnimationFrame(raf);
    };
  }, []);

  const go = (e, id) => {
    e.preventDefault();
    const el = document.getElementById(id);
    if (!el) return;
    const reduce = window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;
    el.scrollIntoView({ behavior: reduce ? "auto" : "smooth", block: "start" });
    const basePath = window.location.pathname + window.location.search;
    window.history.replaceState(null, "", id === "top" ? basePath : `${basePath}#${id}`);
    setActive(id);
  };

  return (
    <nav className={`section-remote ${hidden ? "is-hidden" : ""}`} aria-label="섹션 바로가기">
      {REMOTE_SECTIONS.map((item) => {
        const isActive = active === item.id;
        return (
          <a
            key={item.id}
            href={item.id === "top" ? "#top" : `#${item.id}`}
            className={`section-remote-link ${isActive ? "is-active" : ""}`}
            data-mobile-hidden={item.mobile ? undefined : "true"}
            aria-current={isActive ? "location" : undefined}
            aria-label={`${item.label} 섹션으로 이동`}
            onClick={(e) => go(e, item.id)}
          >
            <span className="section-remote-dot" aria-hidden="true" />
            <span className="section-remote-num" aria-hidden="true">{item.n}</span>
            <span className="section-remote-label">{item.label}</span>
          </a>
        );
      })}
    </nav>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [menuOpen, setMenuOpen] = React.useState(false);
  const [entryActive, setEntryActive] = React.useState(true);

  // Apply theme + dark mode to root
  React.useEffect(() => {
    const root = document.documentElement;
    const theme = THEMES[t.primaryTheme] || THEMES.navy;
    Object.entries(theme).forEach(([k, v]) => root.style.setProperty(k, v));
    root.dataset.dark = t.darkMode ? "1" : "0";
  }, [t.primaryTheme, t.darkMode]);

  React.useEffect(() => {
    const reduce = window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;
    if (reduce) {
      setEntryActive(false);
      return;
    }
    document.documentElement.classList.add("is-entering");
    const done = window.setTimeout(() => {
      setEntryActive(false);
      document.documentElement.classList.remove("is-entering");
      document.documentElement.classList.add("has-entered");
    }, 1350);
    return () => {
      window.clearTimeout(done);
      document.documentElement.classList.remove("is-entering");
    };
  }, []);

  // 스크롤/터치 환경에서도 주요 요소가 자연스럽게 등장하고 반응하도록 한다.
  // 실제 클릭 액션은 그대로 유지하고, reveal/ambient 시각 피드백만 부여한다.
  React.useEffect(() => {
    const reduce = window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;
    if (reduce || !("IntersectionObserver" in window)) return;
    const revealSelector = [
      ".hero-eyebrow-row",
      ".hero-headline",
      ".hero-sub",
      ".hero-ctas",
      ".hero-c-stage",
      ".hero-d-card",
      ".sec-hd",
      ".sw-hd",
      ".about-left",
      ".about-person",
      ".about-quote",
      ".about-val",
      ".about-timeline",
      ".about-timeline-item",
      ".qa-card",
      ".vision-card",
      ".vision-mini-stat",
      ".ach-card",
      ".prom-feat",
      ".prom-tot-item",
      ".prom-card",
      ".integ-card",
      ".integ-item",
      ".news-hd-row",
      ".news-feat",
      ".news-card",
      ".sw-stats",
      ".sw-stat",
      ".sw-feat",
      ".sw-form-wrap",
      ".sw-card",
      ".sw-ticker",
      ".contact-card",
      ".footer-brand",
      ".footer-cols > div",
    ].join(",");
    const ambientSelector = [
      ".qa-card",
      ".about-val",
      ".vision-card",
      ".ach-card",
      ".prom-feat",
      ".prom-card",
      ".integ-card",
      ".news-feat",
      ".news-card",
      ".hero-d-quick-card",
      ".cta",
      ".sw-card",
      ".sw-stat-cta-btn",
      ".contact-channels a",
      ".kakao-fab",
    ].join(",");
    const allSelector = `${revealSelector},${ambientSelector}`;
    const seen = new WeakMap();
    const prepared = new WeakSet();
    const timers = new Set();
    const pulse = (el) => {
      const last = seen.get(el) || 0;
      if (Date.now() - last < 2400) return;
      seen.set(el, Date.now());
      el.classList.add("is-ambient");
      const timer = window.setTimeout(() => {
        el.classList.remove("is-ambient");
        timers.delete(timer);
      }, 1200);
      timers.add(timer);
    };
    const ambientIo = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) pulse(entry.target);
      });
    }, { threshold: 0.42, rootMargin: "0px 0px -8% 0px" });

    const revealIo = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (!entry.isIntersecting) return;
        entry.target.classList.add("reveal-in");
        revealIo.unobserve(entry.target);
      });
    }, { threshold: 0.18, rootMargin: "0px 0px -12% 0px" });

    const markRevealType = (el) => {
      if (el.matches(".about-left, .news-feat, .sw-feat")) el.classList.add("reveal-left");
      if (el.matches(".hero-c-stage, .contact-card, .prom-feat, .sw-form-wrap")) el.classList.add("reveal-scale");
      if (el.matches(".sec-hd, .sw-hd, .news-hd-row")) el.classList.add("reveal-soft");
    };

    const collect = (root) => {
      if (!root) return [];
      if (root === document) return Array.from(document.querySelectorAll(allSelector));
      if (root.nodeType !== 1) return [];
      const el = root;
      const nodes = el.matches?.(allSelector) ? [el] : [];
      return nodes.concat(Array.from(el.querySelectorAll?.(allSelector) || []));
    };

    const prepare = (root = document) => {
      const nodes = collect(root);
      const groupCounts = new Map();
      nodes.forEach((el) => {
        if (el.matches(revealSelector) && !prepared.has(el)) {
          prepared.add(el);
          const parent = el.parentElement || document.body;
          const idx = groupCounts.get(parent) || 0;
          groupCounts.set(parent, idx + 1);
          const delay = el.matches(".sec-hd, .sw-hd, .news-hd-row") ? 0 : Math.min(idx, 8) * 70;
          el.style.setProperty("--reveal-delay", `${delay}ms`);
          markRevealType(el);
          el.classList.add("reveal-prep");
          const rect = el.getBoundingClientRect();
          const alreadyInView = rect.top < window.innerHeight * 0.92 && rect.bottom > 0;
          if (alreadyInView) {
            el.classList.add("reveal-in");
          } else {
            revealIo.observe(el);
          }
        }
        if (el.matches(ambientSelector)) ambientIo.observe(el);
      });
    };

    window.requestAnimationFrame(() => prepare(document));
    const mutationRoot = document.querySelector("main") || document.body;
    const mo = new MutationObserver((records) => {
      records.forEach((record) => {
        record.addedNodes.forEach((node) => prepare(node));
      });
    });
    mo.observe(mutationRoot, { childList: true, subtree: true });

    return () => {
      ambientIo.disconnect();
      revealIo.disconnect();
      mo.disconnect();
      timers.forEach((timer) => window.clearTimeout(timer));
    };
  }, []);

  return (
    <div id="top" className="page">
      <EntryEffect active={entryActive} />
      <GlobalSupportWave />
      <Header onMenuOpen={() => setMenuOpen(true)} catchphrase={t.catchphrase} />
      <MobileMenu open={menuOpen} onClose={() => setMenuOpen(false)} />
      <SectionRemote hidden={menuOpen} />

      <main>
        <SupportHeroFlow />
        <Hero
          variant={t.heroVariant}
          catchphrase={t.catchphrase}
          showPhoto={t.showPhoto}
        />
        <QuickActions />
        <About showPhoto={t.showPhoto} />
        <Vision />
        <Achievements />
        <Promises />
        <Integrity />
        <News showPhoto={t.showPhoto} />
        <SupportWaveSection />
        <Contact />
      </main>

      <Footer />

      {!PROD_MODE && (
      <TweaksPanel title="Tweaks · 시안 옵션">
        <TweakSection label="Hero" />
        <TweakRadio
          label="Hero 변형"
          value={t.heroVariant}
          options={[
            { value: "A", label: "A 임팩트" },
            { value: "B", label: "B 신뢰" },
            { value: "C", label: "C 슬로건" },
            { value: "D", label: "D 명함" },
          ]}
          onChange={(v) => setTweak("heroVariant", v)}
        />
        <TweakText
          label="메인 캐치프레이즈"
          value={t.catchphrase}
          onChange={(v) => setTweak("catchphrase", v)}
        />

        <TweakSection label="Visual" />
        <TweakRadio
          label="Primary 컬러"
          value={t.primaryTheme}
          options={[
            { value: "navy", label: "Navy" },
            { value: "blue", label: "Blue" },
            { value: "mint", label: "Mint" },
          ]}
          onChange={(v) => setTweak("primaryTheme", v)}
        />
        <TweakToggle
          label="다크 모드"
          value={t.darkMode}
          onChange={(v) => setTweak("darkMode", v)}
        />
        <TweakToggle
          label="후보 사진 표시"
          value={t.showPhoto}
          onChange={(v) => setTweak("showPhoto", v)}
        />
      </TweaksPanel>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
