// portal.jsx — Shahdad 2.5D solar system
// Sun (Shahdad / AI core) at center with 16 planets on concentric tilted orbits.
// Depth-sorted so planets pass behind & in front of the sun (true 2.5D).
// Ambient drifting starfield + zodiac constellations + comets behind it all.

const Portal = ({ lang, onOpen }) => {
  const portalRef = React.useRef(null);
  const [size, setSize] = React.useState({ w: 1000, h: 680 });
  const [hover, setHover] = React.useState(null);
  const [isMobile, setIsMobile] = React.useState(() =>
    typeof window !== "undefined" && window.matchMedia && window.matchMedia("(max-width: 700px)").matches);
  const hoverRef = React.useRef(null);
  const pausedRef = React.useRef(false);
  const elapsedRef = React.useRef(0);
  const scaleRef = React.useRef([]);
  const nodeRefs = React.useRef([]);

  // track mobile breakpoint — on phones we render the system static (no rAF) for performance
  React.useEffect(() => {
    if (!window.matchMedia) return;
    const mq = window.matchMedia("(max-width: 700px)");
    const h = () => setIsMobile(mq.matches);
    mq.addEventListener ? mq.addEventListener("change", h) : mq.addListener(h);
    return () => { mq.removeEventListener ? mq.removeEventListener("change", h) : mq.removeListener(h); };
  }, []);

  // measure the portal so the system always fills ~74% of the frame
  React.useEffect(() => {
    const el = portalRef.current;
    if (!el) return;
    const ro = new ResizeObserver((entries) => {
      const r = entries[0].contentRect;
      setSize({ w: r.width, h: r.height });
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  // honour reduced-motion: freeze the system but keep planets laid out
  React.useEffect(() => {
    if (typeof window === "undefined" || !window.matchMedia) return;
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    if (mq.matches) pausedRef.current = true;
  }, []);

  // ---- the 16 planets (inner → outer); Shahdad AI core is the sun ----
  const PLANETS = React.useMemo(() => [
    { id: "aiChat",    icon: "bot",        mat: "m-cyan",   sizeMul: 1.18, fa: "وکیل هوشمند",            ar: "محامٍ ذكي",                 en: "AI Lawyer" },
    { id: "consult",   icon: "chat",       mat: "m-ice",    sizeMul: 1.0,  fa: "مشاوره حقوقی",           ar: "استشارة قانونية",           en: "Consultation" },
    { id: "arb",       icon: "gavel",      mat: "m-violet", sizeMul: 1.02, fa: "هیئت حل اختلاف و داوری", ar: "هيئة التحكيم وحل النزاع",    en: "Arbitration & Panel" },
    { id: "risk",      icon: "shieldAlert",mat: "m-rust",   sizeMul: 0.95, fa: "تحلیل ریسک حقوقی",       ar: "تحليل المخاطر القانونية",   en: "Risk Analysis" },
    { id: "calc",      icon: "calc",       mat: "m-gold",   sizeMul: 1.06, ring: true, fa: "محاسبات مالی حقوقی",     ar: "الحسابات المالية القانونية", en: "Financial Calc" },
    { id: "org",       icon: "building",   mat: "m-slate",  sizeMul: 1.02, ring: true, fa: "SaaS شرکت‌ها",           ar: "SaaS للشركات",              en: "Companies SaaS" },
    { id: "shield",    icon: "shield",     mat: "m-sage",   sizeMul: 0.96, fa: "سپر بیمه حقوقی",         ar: "درع التأمين القانوني",      en: "Legal Insurance" },
    { id: "expert",    icon: "microscope", mat: "m-blue",   sizeMul: 0.95, fa: "کارشناسان و معرفی کارشناس", ar: "الخبراء والدليل الفني",     en: "Experts & Directory" },
    { id: "lawyer",    icon: "scale",      mat: "m-violet", sizeMul: 1.06, fa: "وکیل و معرفی وکلا",       ar: "المحامون والدليل",          en: "Lawyers & Directory" },
    { id: "case",      icon: "briefcase",  mat: "m-cyan",   sizeMul: 0.96, fa: "مدیریت پروژه حقوقی",     ar: "إدارة المشاريع القانونية",  en: "Project Mgmt" },
    { id: "media",     icon: "mic",        mat: "m-gold",   sizeMul: 0.9,  fa: "پادکست حقوقی",           ar: "بودكاست قانوني",            en: "Legal Podcast" },
    { id: "compliance",icon: "shieldCheck",mat: "m-sage",   sizeMul: 0.96, fa: "کامپلاینس حقوقی",        ar: "الامتثال القانوني",         en: "Compliance" },
    { id: "strategy",  icon: "barchart",   mat: "m-ice",    sizeMul: 1.0,  ring: true, fa: "شبیه‌ساز استراتژی و دعاوی", ar: "محاكي الاستراتيجية والدعاوى", en: "Strategy Sim" },
    { id: "contracts", icon: "docEdit",    mat: "m-blue",   sizeMul: 1.0,  fa: "قرارداد هوشمند و ریسک",  ar: "العقد الذكي وتحليل المخاطر", en: "Smart Contracts" },
    { id: "drafting",  icon: "scroll",     mat: "m-violet", sizeMul: 0.9,  fa: "دستیار نگارش حقوقی",     ar: "مساعد الصياغة القانونية",   en: "Drafting Assistant" },
    { id: "social",    icon: "heart",      mat: "m-rust",   sizeMul: 1.06, fa: "سپر اجتماعی حقوقی",      ar: "الدرع الاجتماعي القانوني",  en: "Social Shield" }
  ], []);

  // static starfield — dense, tiny, twinkling (Milky-Way depth); a third twinkle, rest static (cheap)
  const stars = React.useMemo(() => {
    const count = isMobile ? 24 : 36;
    return Array.from({ length: count }, (_, i) => {
      const seed = Math.sin((i + 1) * 91.37) * 10000;
      const rnd = (step) => {
        const n = Math.sin(seed + step * 48.23) * 10000;
        return n - Math.floor(n);
      };
      return {
        id: i,
        x: 4 + rnd(1) * 92,
        y: 4 + rnd(2) * 88,
        s: 1.1 + rnd(3) * 2.2,
        d: (rnd(4) * 5.5).toFixed(2),
        dur: (3.8 + rnd(5) * 3.4).toFixed(2),
        phase: i % 6
      };
    });
  }, [isMobile]);

  // twelve zodiac constellations (برج‌ها) scattered through deep space
  // geometry
  const W = size.w, H = size.h;
  const cx = W / 2, cy = H / 2;
  const tilt = isMobile ? 0.95 : 0.46;                 // minor/major axis → oblique view (near-circular on mobile so front planets separate vertically)
  const rMax = isMobile ? Math.min(W * 0.42, (H / tilt) * 0.46) : Math.min(W * 0.45, (H / tilt) * 0.49);  // outer orbit fills the frame
  const rMin = Math.max(rMax * (isMobile ? 0.24 : 0.34), W * 0.12);  // wider radius spread on mobile → orbits farther apart
  const sunSize = isMobile ? Math.max(58, W * 0.16) : Math.max(72, Math.min(W * 0.142, 168));
  const baseR = isMobile ? Math.max(15, W * 0.042) : Math.max(11, Math.min(W * 0.0161, 18));   // bigger tap targets on mobile

  // mixed orbital directions — some clockwise, some counter-clockwise
  const DIRS = [1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1];

  const orbits = React.useMemo(() => PLANETS.map((p, i) => {
    const f = PLANETS.length > 1 ? i / (PLANETS.length - 1) : 0;
    const radius = rMin + (rMax - rMin) * f;
    const period = 70000 + f * 150000;         // inner ~70s, outer ~220s (all distinct → alignments rare)
    const phase = (i * 137.50776) % 360;       // golden-angle spread → neighbours never clump
    return { radius, period, phase, dir: DIRS[i] || 1 };
  }), [rMin, rMax, PLANETS]);

  // animation loop — positions planets on tilted ellipses, depth-sorts, lerps hover zoom
  React.useEffect(() => {
    let raf, last = performance.now();
    // position one frame; snap=true places instantly (no lerp) for the initial sync pass
    const place = (e, snap) => {
      for (let i = 0; i < orbits.length; i++) {
        const node = nodeRefs.current[i];
        if (!node) continue;
        const o = orbits[i];
        const ang = (o.phase + o.dir * 360 * e / o.period) * Math.PI / 180;
        const px = Math.cos(ang) * o.radius;
        const py = Math.sin(ang) * o.radius * tilt;
        const depth = Math.sin(ang);            // -1 (back) .. 1 (front)
        const front = (depth + 1) / 2;
        const fc = front * front;               // emphasise the front — back planets recede hard
        // desktop: back planets less tiny (looks nicer); mobile: stronger recession to clear space
        const minS = isMobile ? 0.30 : 0.46;
        let targetS = minS + (isMobile ? 1.0 : 0.86) * fc;
        let z = Math.round(1000 + depth * 900);
        let op = (isMobile ? 0.14 : 0.34) + (isMobile ? 0.86 : 0.66) * fc;
        let lblop = Math.max(0, (front - (isMobile ? 0.80 : 0.70)) / (isMobile ? 0.20 : 0.30));  // front 2-3 planets named
        if (hoverRef.current === i) { targetS = Math.max(targetS * 1.7, 1.5); z = 99999; op = 1; lblop = 1; }
        const cur = (snap || scaleRef.current[i] == null) ? targetS : scaleRef.current[i];
        const ns = cur + (targetS - cur) * 0.16;
        scaleRef.current[i] = ns;
        node.style.transform = `translate3d(${(cx + px).toFixed(1)}px, ${(cy + py).toFixed(1)}px, 0)`;
        node.style.zIndex = z;
        node.style.opacity = op.toFixed(3);
        node.style.setProperty("--s", ns.toFixed(3));
        node.style.setProperty("--lo", lblop.toFixed(3));
      }
    };
    // initial synchronous placement — works even if the tab is hidden and RAF never fires
    place(elapsedRef.current, true);
    const loop = (now) => {
      const dt = Math.min(now - last, 64); last = now;
      if (!pausedRef.current) elapsedRef.current += dt;
      place(elapsedRef.current, false);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [orbits, cx, cy, tilt, isMobile]);

  const enter = (i) => { hoverRef.current = i; pausedRef.current = true; setHover(i); };
  const leave = () => {
    hoverRef.current = null; setHover(null);
    const mq = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)");
    pausedRef.current = mq && mq.matches ? true : false;
  };

  return (
    <div className="portal solar" ref={portalRef}>
      {/* ---- ambient deep-space background ---- */}
      <div className="space-bg" aria-hidden="true">
        <div className="starfield">
          {stars.map((st) =>
            <i key={st.id} className={"star twinkle-star phase-" + st.phase} style={{
              left: st.x + "%", top: st.y + "%", width: st.s + "px", height: st.s + "px",
              "--tw": st.dur + "s", animationDelay: st.d + "s"
            }}></i>
          )}
        </div>
      </div>

      {/* three racing neon lines around the portal frame — each splits into thin threads then merges */}
      <div className="portal-frame f1" aria-hidden="true"><i className="pf-thread t-a"></i></div>
      <div className="portal-frame f2" aria-hidden="true"><i className="pf-thread t-a"></i></div>
      <div className="portal-frame f3" aria-hidden="true"><i className="pf-thread t-a"></i></div>

      {/* ---- the solar system ---- */}
      <div className="solar-stage">
        {/* orbit ellipses */}
        <svg className="orbit-lines" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" aria-hidden="true">
          {orbits.map((o, i) =>
            <ellipse key={i} cx={cx} cy={cy} rx={o.radius} ry={o.radius * tilt}
              className={"orbit-ell ov" + (i % 5) + (hover === i ? " on" : "")} />)}
        </svg>

        {/* the sun — Shahdad AI core */}
        <button className="sun-core" style={{ width: sunSize, height: sunSize, left: cx, top: cy }}
          title={lang === "fa" ? "دستیار هوشمند حقوقی شهداد" : lang === "ar" ? "مساعد شهداد القانوني الذكي" : "Shahdad AI Legal Assistant"}
          onClick={() => onOpen("aiChat")}>
          <span className="sun-corona"></span>
          <span className="sun-flare"></span>
          <span className="sun-body"></span>
          <span className="sun-ai">AI</span>
          <span className="sun-label">SHAHDAD</span>
        </button>

        {/* planets */}
        {PLANETS.map((p, i) => {
          const Icon = Ic[p.icon] || Ic.chip;
          const d = baseR * 2 * p.sizeMul;
          return (
            <div key={p.id} className={"planet-node" + (hover === i ? " hovered" : "")}
              ref={(el) => nodeRefs.current[i] = el}
              onMouseEnter={() => enter(i)} onMouseLeave={leave}
              onClick={() => onOpen(p.id)}>
              <span className={"planet-body " + p.mat} style={{ width: d, height: d }}>
                {p.ring && <span className="planet-ring"></span>}
                <Icon size={Math.max(13, d * 0.56)} className="planet-ico" />
              </span>
              <span className="planet-label" style={{ top: baseR * p.sizeMul + 7 }}>{p[lang]}</span>
            </div>);
        })}
      </div>

      <div className="portal-footer">
        <button className="pfoot-btn" onClick={() => { AudioCtl.open(); onOpen("about"); }}>
          <Ic.info size={15} />
          <span>{lang === "fa" ? "درباره ما" : lang === "ar" ? "عن شهداد" : "About Us"}</span>
        </button>
      </div>

      <div className="portal-hint" aria-hidden="true">
        {lang === "fa" ? "روی هر سیاره بزنید تا باز شود" : lang === "ar" ? "اضغط على أي كوكب لفتحه" : "Tap any planet to open it"}
      </div>
    </div>);
};

window.Portal = Portal;
