// Reusable components for Eastwest Vanguard
const { useState, useEffect, useRef, useCallback, useMemo } = React;

// ───────── Language context (simple) ─────────
const LangCtx = React.createContext({ lang: "en", t: window.I18N.en, setLang: () => {} });

function LangProvider({ children }) {
  const [lang, setLangState] = useState(() => localStorage.getItem("ewv-lang") || "en");
  useEffect(() => {
    document.body.setAttribute("data-lang", lang);
    localStorage.setItem("ewv-lang", lang);
  }, [lang]);
  const setLang = useCallback((l) => setLangState(l), []);
  const t = window.I18N[lang];
  return <LangCtx.Provider value={{ lang, t, setLang }}>{children}</LangCtx.Provider>;
}
const useLang = () => React.useContext(LangCtx);

// ───────── Route context (hash routing) ─────────
const RouteCtx = React.createContext({ route: "home", setRoute: () => {} });

function RouteProvider({ children }) {
  const initial = () => (window.location.hash || "#home").replace("#", "") || "home";
  const [route, setRouteState] = useState(initial);
  useEffect(() => {
    const onHash = () => setRouteState(initial());
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  const setRoute = useCallback((r) => {
    window.location.hash = "#" + r;
    window.scrollTo({ top: 0, behavior: "instant" });
  }, []);
  return <RouteCtx.Provider value={{ route, setRoute }}>{children}</RouteCtx.Provider>;
}
const useRoute = () => React.useContext(RouteCtx);

// ───────── Header ─────────
function Header({ mode = "dark" }) {
  const { lang, setLang, t } = useLang();
  const { route, setRoute } = useRoute();
  const [scrolled, setScrolled] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [scrollProgress, setScrollProgress] = useState(0);

  useEffect(() => {
    const onScroll = () => {
      setScrolled(window.scrollY > 12);
      const doc = document.documentElement;
      const max = Math.max(1, doc.scrollHeight - window.innerHeight);
      setScrollProgress(Math.min(1, Math.max(0, window.scrollY / max)));
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  // lock body scroll while drawer is open
  useEffect(() => {
    document.body.setAttribute("data-menu-open", menuOpen ? "true" : "false");
    return () => document.body.removeAttribute("data-menu-open");
  }, [menuOpen]);

  // close drawer when route changes
  useEffect(() => { setMenuOpen(false); }, [route]);

  const items = [
    { k: "about", l: t.nav.about },
    { k: "services", l: t.nav.services },
    { k: "asian", l: t.nav.asian },
    { k: "western", l: t.nav.western },
    { k: "cases", l: t.nav.cases },
    { k: "community", l: t.nav.community },
    { k: "contact", l: t.nav.contact },
  ];

  const dark = mode === "dark";
  const isHome = route === "home";
  const fg = dark ? "var(--ivory)" : "var(--navy)";
  const fgMute = dark ? "rgba(245,239,227,0.72)" : "rgba(10,24,48,0.62)";
  const borderColor = dark ? "rgba(245,239,227,0.14)" : "rgba(10,24,48,0.10)";
  const bgScrolled = dark ? "rgba(17,22,26,0.88)" : "rgba(248,246,241,0.92)";
  const bgInitial  = (isHome && dark) ? "rgba(17,22,26,0.22)" : "transparent";
  const headerColor = menuOpen ? "var(--ivory)" : fg;

  const headerStyle = {
    position: "fixed", top: 0, left: 0, right: 0, zIndex: 60,
    color: headerColor,
    background: menuOpen ? "transparent" : (scrolled ? bgScrolled : bgInitial),
    backdropFilter: (menuOpen || (!scrolled && !isHome)) ? "none" : "blur(14px) saturate(140%)",
    WebkitBackdropFilter: (menuOpen || (!scrolled && !isHome)) ? "none" : "blur(14px) saturate(140%)",
    borderBottom: (scrolled && !menuOpen) ? `1px solid ${borderColor}` : "1px solid transparent",
    transition: "background 240ms ease, border-color 240ms ease, backdrop-filter 240ms ease, color 240ms ease",
  };

  return (
    <React.Fragment>
      <header style={headerStyle}>
        <div className="ewv-header-inner" style={{
          maxWidth: 1440, margin: "0 auto",
          padding: "20px 48px",
          display: "grid", gridTemplateColumns: "1fr auto 1fr", alignItems: "center", gap: 32,
        }}>
          {/* Brand */}
          <a href="#home" onClick={(e) => { e.preventDefault(); setRoute("home"); }}
             style={{ display: "flex", alignItems: "center", gap: 12, justifySelf: "start" }}>
            <Mark color={headerColor} size={26} />
            <div style={{ lineHeight: 1 }}>
              <div className="serif" style={{ fontSize: 18, letterSpacing: "0.04em", fontWeight: 500 }}>
                {t.brand}
              </div>
              <div className="ewv-brand-tagline" style={{ fontSize: 10, letterSpacing: "0.22em", color: menuOpen ? "rgba(245,239,227,0.6)" : fgMute, marginTop: 4, textTransform: "uppercase" }}>
                {t.tagline}
              </div>
            </div>
          </a>

          {/* Desktop nav */}
          <nav className="ewv-nav-desktop" style={{ display: "flex", gap: 22, fontSize: 13, letterSpacing: "0.02em" }}>
            {items.map(it => (
              <a key={it.k} href={"#" + it.k}
                 onClick={(e) => { e.preventDefault(); setRoute(it.k); }}
                 style={{
                   color: route === it.k ? fg : fgMute,
                   transition: "color 160ms",
                   position: "relative",
                   paddingBottom: 2,
                   fontWeight: route === it.k ? 600 : 400,
                   whiteSpace: "nowrap",
                 }}
                 onMouseEnter={e => e.currentTarget.style.color = fg}
                 onMouseLeave={e => e.currentTarget.style.color = route === it.k ? fg : fgMute}>
                {it.l}
                {route === it.k && (
                  <span style={{
                    position: "absolute", left: 0, right: 0, bottom: -6, height: 1,
                    background: "var(--gold)",
                  }} />
                )}
              </a>
            ))}
          </nav>

          {/* Lang + CTA + Hamburger */}
          <div style={{ display: "flex", alignItems: "center", gap: 12, justifySelf: "end" }}>
            <div style={{
              display: "flex", alignItems: "center", gap: 0,
              border: `1px solid ${menuOpen ? "rgba(245,239,227,0.22)" : borderColor}`,
              borderRadius: 999, padding: 3, fontSize: 11, letterSpacing: "0.08em",
            }}>
              {[["en","EN"],["zh","中"]].map(([k, label]) => (
                <button key={k} onClick={() => setLang(k)}
                  style={{
                    padding: "5px 12px", borderRadius: 999,
                    background: lang === k ? (dark || menuOpen ? "var(--ivory)" : "var(--navy)") : "transparent",
                    color: lang === k ? (dark || menuOpen ? "var(--navy)" : "var(--ivory)") : headerColor,
                    fontWeight: lang === k ? 600 : 500,
                    transition: "all 160ms",
                  }}>{label}</button>
              ))}
            </div>
            <button className="ewv-header-cta" onClick={() => setRoute("contact")}
              style={{
                padding: "10px 18px", fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase",
                background: "var(--gold)", color: "var(--navy)",
                border: "1px solid var(--gold)",
                fontWeight: 600,
                transition: "all 180ms",
              }}
              onMouseEnter={e => { e.currentTarget.style.background = "transparent"; e.currentTarget.style.color = fg; }}
              onMouseLeave={e => { e.currentTarget.style.background = "var(--gold)"; e.currentTarget.style.color = "var(--navy)"; }}>
              {t.cta.book}
            </button>

            {/* Hamburger toggle — CSS-shown on tablet/mobile only */}
            <button
              className="ewv-hamburger"
              data-open={menuOpen ? "true" : "false"}
              aria-label={menuOpen ? (lang === "zh" ? "关闭菜单" : "Close menu") : (lang === "zh" ? "打开菜单" : "Open menu")}
              aria-expanded={menuOpen}
              onClick={() => setMenuOpen(o => !o)}
              style={{ color: headerColor }}
            >
              <span />
            </button>
          </div>
        </div>
        <span
          aria-hidden
          className="ewv-scroll-progress"
          style={{
            transform: `scaleX(${scrollProgress})`,
            opacity: (scrolled || scrollProgress > 0.02) && !menuOpen ? 1 : 0,
          }}
        />
      </header>

      {/* Mobile drawer */}
      <div
        className="ewv-mobile-drawer"
        data-open={menuOpen ? "true" : "false"}
        aria-hidden={!menuOpen}
      >
        <nav>
          {items.map(it => (
            <a key={it.k} href={"#" + it.k}
               data-active={route === it.k ? "true" : "false"}
               onClick={(e) => { e.preventDefault(); setRoute(it.k); }}>
              {it.l}
            </a>
          ))}
        </nav>
        <div className="ewv-drawer-foot">
          <button onClick={() => setRoute("contact")}
            style={{
              padding: "18px 22px", fontSize: 12, letterSpacing: "0.16em", textTransform: "uppercase",
              background: "var(--gold)", color: "var(--navy)",
              fontWeight: 700,
              border: "1px solid var(--gold)",
              width: "100%",
            }}>{t.cta.book} →</button>
          <div style={{
            display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 10,
            fontSize: 11, letterSpacing: "0.22em", color: "rgba(245,239,227,0.5)",
            paddingTop: 8,
          }}>
            <span>{lang === "zh" ? "EW · VG — 年度案卷" : "EW · VG — VOL. 01"} / {new Date().getFullYear()}</span>
            <span style={{ color: "var(--gold)", whiteSpace: "nowrap" }}>東 · EAST — WEST · 西</span>
          </div>
        </div>
      </div>
    </React.Fragment>
  );
}

// ───────── Logo mark ─────────
function Mark({ color = "var(--navy)", size = 28 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 40 40" fill="none">
      <circle cx="20" cy="20" r="19" stroke={color} strokeWidth="1" />
      <path d="M8 20 Q 20 6, 32 20" stroke={color} strokeWidth="1" fill="none" />
      <path d="M8 20 Q 20 34, 32 20" stroke={color} strokeWidth="1" fill="none" />
      <line x1="20" y1="2" x2="20" y2="38" stroke={color} strokeWidth="1" opacity="0.4" />
      <circle cx="20" cy="20" r="2" fill="var(--gold)" />
    </svg>
  );
}

// ───────── Footer ─────────
function Footer({ bare = false }) {
  const { t, lang } = useLang();
  const { setRoute } = useRoute();
  const legal = t.footer.legal || ["Privacy", "Terms"];
  return (
    <footer style={{
      background: "var(--navy)", color: "var(--ivory)",
      position: "relative", overflow: "hidden",
    }}>
      {/* Inner-page footer: a single EVEN vertical sheen — uniform across the
         width, so there is no photo "block" / color seam. Home (bare) stays flat. */}
      {!bare && (
        <div aria-hidden style={{
          position: "absolute", inset: 0,
          background: "linear-gradient(180deg, rgba(34,40,44,0.55) 0%, rgba(17,22,26,0) 44%)",
          pointerEvents: "none",
        }} />
      )}
      <div className="ewv-footer-pad" style={{ maxWidth: 1440, margin: "0 auto", padding: "100px 48px 48px", position: "relative" }}>
        <div className="ewv-footer-grid" style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr", gap: 56, alignItems: "start" }}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 24 }}>
              <Mark color="var(--ivory)" size={32} />
              <div>
                <div className="serif" style={{ fontSize: 22, letterSpacing: "0.04em" }}>{t.brand}</div>
                <div style={{ fontSize: 10, letterSpacing: "0.22em", color: "rgba(245,239,227,0.6)", marginTop: 4, textTransform: "uppercase" }}>
                  {t.tagline}
                </div>
              </div>
            </div>
            <p className="serif ewv-footer-tagline" style={{
              fontSize: 22, lineHeight: 1.35, fontStyle: "italic",
              color: "rgba(245,239,227,0.88)", maxWidth: 340, margin: 0,
            }}>
              "{t.footer.tagline}"
            </p>
          </div>
          {t.footer.cols.map((col, i) => (
            <div key={i}>
              <div style={{
                fontSize: 10, letterSpacing: "0.22em", textTransform: "uppercase",
                color: "var(--gold)", marginBottom: 18,
              }}>{col.h}</div>
              <ul style={{ listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 10 }}>
                {col.l.map((item, j) => (
                  <li key={j} style={{ fontSize: 14, color: "rgba(245,239,227,0.78)" }}>{item}</li>
                ))}
              </ul>
            </div>
          ))}
        </div>
        <div className="ewv-footer-bottom" style={{
          marginTop: 80, paddingTop: 28,
          borderTop: "1px solid rgba(245,239,227,0.14)",
          display: "flex", justifyContent: "space-between", alignItems: "center",
          fontSize: 12, color: "rgba(245,239,227,0.55)",
        }}>
          <div>{t.footer.copy}</div>
          <div style={{ display: "flex", gap: 24, letterSpacing: "0.06em", flexWrap: "wrap" }}>
            <span>{legal[0]}</span>
            <span>{legal[1]}</span>
            <span style={{ color: "var(--gold)" }}>{lang === "zh" ? "中 · EN" : "EN · 中"}</span>
          </div>
        </div>
      </div>
    </footer>
  );
}

// ───────── Section atoms ─────────
function SectionEyebrow({ children, color = "var(--gold)" }) {
  return (
    <div style={{
      fontSize: 11, letterSpacing: "0.28em", textTransform: "uppercase",
      color, fontWeight: 500,
    }}>{children}</div>
  );
}

function Divider({ color = "var(--line)" }) {
  return <div style={{ height: 1, background: color, width: "100%" }} />;
}

// ───────── Animated reveal ─────────
function Reveal({ children, delay = 0, as = "div", style = {} }) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      (entries) => entries.forEach(e => e.isIntersecting && setVisible(true)),
      { threshold: 0.12 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const Comp = as;
  return (
    <Comp ref={ref} style={{
      ...style,
      opacity: visible ? 1 : 0,
      transform: visible ? "translateY(0)" : "translateY(24px)",
      filter: visible ? "blur(0px)" : "blur(9px)",
      willChange: "opacity, transform, filter",
      transition: `opacity 760ms ease ${delay}ms, transform 760ms cubic-bezier(.16,.84,.24,1) ${delay}ms, filter 900ms ease ${delay}ms`,
    }}>{children}</Comp>
  );
}

// ───────── Refined motion primitives (shared; used by home-below-hero + inner pages) ─────────
// One-shot "has entered viewport" flag — drives hairline draws, clip reveals, etc.
function useInView(threshold = 0.2) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      (entries) => entries.forEach(e => { if (e.isIntersecting) setSeen(true); }),
      { threshold }
    );
    io.observe(el);
    return () => io.disconnect();
  }, [threshold]);
  return [ref, seen];
}

// Subtle scroll parallax. Attach the returned ref to an OVERSIZED absolute layer
// (e.g. inset:-10%) so the translate never reveals an edge. strength≈px/viewport.
function useParallax(strength = 28) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let raf = 0;
    const update = () => {
      raf = 0;
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || 800;
      const center = r.top + r.height / 2;
      const prog = (center - vh / 2) / (vh / 2 + r.height / 2); // -1..1
      el.style.transform = `translate3d(0, ${(-prog * strength).toFixed(2)}px, 0)`;
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); };
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [strength]);
  return ref;
}

// A gold hairline that draws in (scaleX 0→1) the first time it enters view.
function DrawLine({ width = 40, height = 1, color = "var(--gold)", delay = 0, style = {} }) {
  const [ref, seen] = useInView(0.6);
  return (
    <span ref={ref} aria-hidden style={{
      display: "inline-block", width, height, background: color,
      transformOrigin: "left center",
      transform: seen ? "scaleX(1)" : "scaleX(0)",
      transition: `transform 700ms cubic-bezier(.2,.7,.2,1) ${delay}ms`,
      ...style,
    }} />
  );
}

// ───────── Image placeholder (since we have no real assets) ─────────
// A composed SVG "city / east-meets-west" hero image, very abstract.
function HeroImage({ style = {} }) {
  return (
    <div className="ewv-hero-crop" style={{
      position: "relative", width: "100%", height: "100%",
      overflow: "hidden",
      background: "var(--graphite)",
      ...style,
    }}>
      <div className="ewv-hero-image-layer" style={{
        position: "absolute", inset: "-2%",
        backgroundImage: "url('uploads/ewv-bridge-luxury.png')",
        backgroundSize: "cover",
        backgroundPosition: "center center",
        backgroundRepeat: "no-repeat",
      }} />
      <div style={{
        position: "absolute", inset: 0,
        background: "linear-gradient(90deg, rgba(17,22,26,0.78) 0%, rgba(17,22,26,0.44) 34%, rgba(17,22,26,0.10) 64%, rgba(17,22,26,0.22) 100%)",
        pointerEvents: "none",
      }} />
      <div style={{
        position: "absolute", inset: 0,
        background: "linear-gradient(180deg, rgba(17,22,26,0.42) 0%, rgba(17,22,26,0.08) 42%, rgba(17,22,26,0.54) 100%)",
        pointerEvents: "none",
      }} />
      <div className="ewv-hero-grain" style={{ position: "absolute", inset: 0, pointerEvents: "none" }} />
      <div style={{
        position: "absolute", left: "6%", right: "8%", bottom: "12%", height: 1,
        background: "linear-gradient(90deg, rgba(242,239,232,0), rgba(242,239,232,0.36), rgba(183,163,109,0.18), rgba(242,239,232,0))",
        pointerEvents: "none",
      }} />
    </div>
  );
}
function SkylineSVG() {
  return (
    <svg viewBox="0 0 1600 900" preserveAspectRatio="xMidYMax slice"
      style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}>
      <defs>
        <linearGradient id="hg" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#0A1830" stopOpacity="0" />
          <stop offset="70%" stopColor="#0A1830" stopOpacity="0.5" />
          <stop offset="100%" stopColor="#0A1830" stopOpacity="0.95" />
        </linearGradient>
        <linearGradient id="bg-east" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#1E3358" />
          <stop offset="100%" stopColor="#0A1830" />
        </linearGradient>
      </defs>
      {/* Distant skyline */}
      <g opacity="0.42" fill="#1E3358">
        {Array.from({ length: 24 }).map((_, i) => {
          const x = i * 70;
          const h = 80 + ((i * 53) % 180);
          return <rect key={i} x={x} y={900 - h - 200} width={56} height={h} />;
        })}
      </g>
      {/* Mid skyline */}
      <g opacity="0.7" fill="#142847">
        {Array.from({ length: 18 }).map((_, i) => {
          const x = i * 92 + 18;
          const h = 140 + ((i * 71) % 240);
          return <rect key={i} x={x} y={900 - h - 90} width={70} height={h} />;
        })}
      </g>
      {/* Front skyline */}
      <g fill="#0A1830">
        {Array.from({ length: 14 }).map((_, i) => {
          const x = i * 120;
          const h = 180 + ((i * 89) % 320);
          return <rect key={i} x={x} y={900 - h} width={96} height={h} />;
        })}
      </g>
      {/* Window lights - warm on right, cool on left */}
      <g>
        {Array.from({ length: 60 }).map((_, i) => {
          const x = (i * 137) % 1600;
          const y = 500 + ((i * 53) % 300);
          const warm = x > 800;
          return <rect key={i} x={x} y={y} width={3} height={3}
            fill={warm ? "#C9A24A" : "#8FB3D9"} opacity={0.4 + ((i * 13) % 50) / 100} />;
        })}
      </g>
      {/* Sun/moon */}
      <circle cx="1180" cy="240" r="80" fill="rgba(201,162,74,0.16)" />
      <circle cx="1180" cy="240" r="46" fill="rgba(201,162,74,0.28)" />
      {/* East mountain silhouette (subtle pagoda-style peaks) */}
      <path d="M 1100 700 L 1180 580 L 1210 620 L 1260 540 L 1310 600 L 1380 510 L 1450 590 L 1520 530 L 1600 600 L 1600 900 L 1100 900 Z"
        fill="#0A1830" opacity="0.65" />
      {/* Top fade */}
      <rect x="0" y="0" width="1600" height="900" fill="url(#hg)" />
    </svg>
  );
}

// ───────── Decorative arc separator ─────────
function ArcDivider({ flip = false, color = "var(--ivory)" }) {
  return (
    <svg viewBox="0 0 1440 80" preserveAspectRatio="none"
      style={{ display: "block", width: "100%", height: 60,
        transform: flip ? "rotate(180deg)" : "none" }}>
      <path d="M0,80 C 360,0 1080,0 1440,80 L1440,80 L0,80 Z" fill={color} />
    </svg>
  );
}

// ───────── Number ticker (counts up the first time it enters view) ─────────
function NumberDisplay({ value }) {
  // value can be "17", "2,000+", "100+", "1"
  const ref = useRef(null);
  const [disp, setDisp] = useState(String(value));
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const m = String(value).match(/^(\D*)([\d,]+)(.*)$/);
    if (!m) { setDisp(String(value)); return; }
    const prefix = m[1], target = parseInt(m[2].replace(/,/g, ""), 10), suffix = m[3];
    const fmt = (n) => prefix + n.toLocaleString("en-US") + suffix;
    setDisp(fmt(0));
    let raf = 0, t0 = null, done = false;
    const ease = (t) => 1 - Math.pow(1 - t, 3);
    const dur = 1500;
    const tick = (now) => {
      if (t0 === null) t0 = now;
      const t = Math.min(1, (now - t0) / dur);
      setDisp(fmt(Math.round(ease(t) * target)));
      if (t < 1) raf = requestAnimationFrame(tick); else setDisp(fmt(target));
    };
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !done) { done = true; raf = requestAnimationFrame(tick); }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => { io.disconnect(); if (raf) cancelAnimationFrame(raf); };
  }, [value]);
  return (
    <div ref={ref} className="serif mono-num" style={{
      fontSize: "clamp(48px, 6vw, 92px)",
      lineHeight: 1, letterSpacing: 0,
      color: "var(--gold)",
      fontWeight: 500,
    }}>{disp}</div>
  );
}

Object.assign(window, {
  LangCtx, LangProvider, useLang,
  RouteCtx, RouteProvider, useRoute,
  Header, Footer, Mark,
  SectionEyebrow, Divider, Reveal,
  useInView, useParallax, DrawLine,
  HeroImage, ArcDivider, NumberDisplay,
});
