// Main app: language toggle, palette/font wiring, page sections.
// Booking section is imported from booking.jsx.

const { useState, useEffect, useMemo, useRef } = React;

// booking.jsx loads first and assigns window.Booking. Pull it into this
// script's scope so JSX can use the bare name.
const Booking = window.Booking;
const { useTweaks, TweaksPanel, TweakSection, TweakRadio, TweakToggle } = window;

// ── Design system ───────────────────────────────────────────────────────────
// Palettes share structure so a swap is a CSS-var change, no component edits.
// Keys: bg, surface, ink, mute, line, accent, accentInk, soft.

const PALETTES = {
  bloom: {
    label: "Bloom",
    // Sampled directly from the brand social posts: bg #eee9e6. Surface
    // kept very close to bg so section bands don't introduce a tonal step.
    bg: "#eee9e6",
    surface: "#f1ece8",
    ink: "#2a1a1d",
    mute: "#8a6a6a",
    line: "#dcd4d2",
    accent: "#bf6060",
    accentInk: "#f7f0ee",
    soft: "#e8a89e",
  },
  sage: {
    label: "Sage",
    // Tetradic +90° from #bf6060 (warm red → olive/sage). Background/ink stay
    // in the warm family so the swap feels like an accent change, not a
    // different brand.
    bg: "#ebebe2",
    surface: "#f2f2eb",
    ink: "#1f221a",
    mute: "#6b7560",
    line: "#d6d6c9",
    accent: "#6b8a4d",
    accentInk: "#f1f4ec",
    soft: "#c0d098",
  },
  sea: {
    label: "Sea",
    // Tetradic +180° from #bf6060 (warm red → teal).
    bg: "#e3ebec",
    surface: "#ecf2f3",
    ink: "#19262a",
    mute: "#5e7479",
    line: "#ccd5d6",
    accent: "#4d8a8a",
    accentInk: "#ecf3f4",
    soft: "#a8cdd0",
  },
};

const FONTS = {
  editorial: {
    label: "Editorial",
    display: "'Instrument Serif', 'Times New Roman', serif",
    body: "'Geist', 'Helvetica Neue', Helvetica, sans-serif",
    mono: "'Geist Mono', ui-monospace, monospace",
  },
  quiet: {
    label: "Quiet",
    display: "'Newsreader', 'Times New Roman', serif",
    body: "'Manrope', 'Helvetica Neue', Helvetica, sans-serif",
    mono: "'Geist Mono', ui-monospace, monospace",
  },
};

// ── Language helpers ────────────────────────────────────────────────────────

function detectLang() {
  try {
    const stored = localStorage.getItem("psico.lang");
    if (stored === "en" || stored === "es") return stored;
  } catch (e) {}
  const n = (navigator.language || "en").toLowerCase();
  return n.startsWith("es") ? "es" : "en";
}

function useLang() {
  const [lang, setLang] = useState(detectLang);
  useEffect(() => {
    document.documentElement.lang = lang;
    try { localStorage.setItem("psico.lang", lang); } catch (e) {}
  }, [lang]);
  const t = window.COPY[lang];
  return [lang, setLang, t];
}

// ── Theme injection ─────────────────────────────────────────────────────────
// Writes palette + fonts to :root as CSS vars. Sections read them via var().

function ThemeStyle({ palette, fonts }) {
  const p = PALETTES[palette] || PALETTES.sage;
  const f = FONTS[fonts] || FONTS.editorial;
  const css = `
    :root {
      --bg: ${p.bg};
      --surface: ${p.surface};
      --ink: ${p.ink};
      --mute: ${p.mute};
      --line: ${p.line};
      --accent: ${p.accent};
      --accent-ink: ${p.accentInk};
      --soft: ${p.soft};
      --f-display: ${f.display};
      --f-body: ${f.body};
      --f-mono: ${f.mono};
    }
  `;
  return <style>{css}</style>;
}

// ── Reusable atoms ──────────────────────────────────────────────────────────

function Eyebrow({ children }) {
  return <div className="ps-eyebrow">{children}</div>;
}

function SectionTitle({ children }) {
  if (typeof children === "string") {
    return <h2 className="ps-h2"><MarkerText text={children} /></h2>;
  }
  return <h2 className="ps-h2">{children}</h2>;
}

function Button({ children, kind = "primary", as = "button", ...rest }) {
  const cls = "ps-btn ps-btn-" + kind;
  if (as === "a") return <a className={cls} {...rest}>{children}</a>;
  return <button className={cls} {...rest}>{children}</button>;
}

// ── Marker emphasis ─────────────────────────────────────────────────────────
// `*word*` segments in copy strings render as italic text with a brushstroke
// underline in the brand accent color. Matches the typographic emphasis style
// on @psic.alepalomo social posts.

function MarkerEm({ children }) {
  return <em className="ps-mk">{children}</em>;
}

function MarkerText({ text }) {
  if (!text) return null;
  const parts = String(text).split(/(\*[^*]+\*)/g);
  return (
    <>
      {parts.map((p, i) => {
        if (p.length > 2 && p.startsWith("*") && p.endsWith("*")) {
          return <MarkerEm key={i}>{p.slice(1, -1)}</MarkerEm>;
        }
        return <React.Fragment key={i}>{p}</React.Fragment>;
      })}
    </>
  );
}

// Make available to booking.jsx (separate babel script scope).
Object.assign(window, { MarkerEm, MarkerText });

// ── Scroll reveal ───────────────────────────────────────────────────────────
// Single-shot fade-up on viewport entry. Add to any element with `<Reveal>...`.

function Reveal({ children, delay = 0, className = "" }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    const reveal = () => el.classList.add("is-revealed");

    // Synchronous viewport check: IntersectionObserver doesn't fire callbacks
    // when document.hidden is true (background tabs, prerendered iframes),
    // and even when visible it can lag a frame, leaving content stuck at
    // opacity 0. If we're already in view on mount, reveal immediately.
    const rect = el.getBoundingClientRect();
    const vh = window.innerHeight || document.documentElement.clientHeight;
    if (rect.top < vh * 0.95 && rect.bottom > 0) {
      reveal();
      return;
    }

    if (typeof IntersectionObserver === "undefined") {
      reveal();
      return;
    }

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          reveal();
          io.disconnect();
        }
      });
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);

    // Safety net: if IO never fires (hidden document, very slow load), don't
    // leave content invisible forever.
    const fallback = setTimeout(reveal, 2000);

    return () => {
      io.disconnect();
      clearTimeout(fallback);
    };
  }, []);
  return (
    <div
      ref={ref}
      className={"reveal " + className}
      style={delay ? { transitionDelay: delay + "ms" } : null}
    >
      {children}
    </div>
  );
}

// ── Scroll state ────────────────────────────────────────────────────────────
function useScrolled(threshold = 80) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const on = () => setScrolled(window.scrollY > threshold);
    on();
    window.addEventListener("scroll", on, { passive: true });
    return () => window.removeEventListener("scroll", on);
  }, [threshold]);
  return scrolled;
}

// ── Header ──────────────────────────────────────────────────────────────────

function Header({ lang, setLang, t, layout, onBook }) {
  const scrolled = useScrolled();
  const navItems = [
    { href: "#about", k: t.nav.about },
    { href: "#approach", k: t.nav.approach },
    { href: "#services", k: t.nav.services },
    { href: "#book", k: t.nav.book },
    { href: "#contact", k: t.nav.contact },
  ];

  const langBtn = (
    <button
      type="button"
      className="ps-lang"
      aria-label={t.langToggle.aria}
      onClick={() => setLang(lang === "en" ? "es" : "en")}
    >
      <span aria-hidden="true">{lang === "en" ? "EN" : "ES"}</span>
      <span className="ps-lang-sep">/</span>
      <span aria-hidden="true" className="ps-lang-alt">{t.langToggle.label}</span>
    </button>
  );

  const logo = (
    <a href="#top" className="ps-logo" aria-label="Home">
      <span className="ps-logo-mark" aria-hidden="true" />
      <span className="ps-logo-name">Ale Palomo</span>
      <span className="ps-logo-role">{lang === "en" ? "Clinical psychologist" : "Psicóloga clínica"}</span>
    </a>
  );

  const headerCls = (base) => base + (scrolled ? " ps-header-scrolled" : "");

  if (layout === "centered") {
    return (
      <header className={headerCls("ps-header ps-header-centered")} data-screen-label="Header">
        <div className="ps-header-row ps-header-row-top">
          {logo}
          <div className="ps-header-utils">
            {langBtn}
            <Button kind="onaccent" as="a" href="#book" onClick={onBook}>{t.nav.bookCta}</Button>
          </div>
        </div>
        <nav className="ps-nav ps-nav-centered" aria-label="Primary">
          {navItems.map((n) => <a key={n.href} href={n.href}>{n.k}</a>)}
        </nav>
      </header>
    );
  }

  // Classic: cream zone on left wraps logo; brick block on the right holds
  // nav, lang toggle, and CTA. The hard edge meets right where the logo's
  // role-pipe lives, so the two zones read as one composed band, not as a
  // floating logo + floating menu.
  return (
    <header className={headerCls("ps-header ps-header-classic")} data-screen-label="Header">
      <div className="ps-header-cream">
        {logo}
      </div>
      <div className="ps-header-block">
        <nav className="ps-nav" aria-label="Primary">
          {navItems.map((n) => <a key={n.href} href={n.href}>{n.k}</a>)}
        </nav>
        <span className="ps-header-divider" aria-hidden="true" />
        <div className="ps-header-utils">
          {langBtn}
          <Button kind="onaccent" as="a" href="#book" onClick={onBook}>{t.nav.bookCta}</Button>
        </div>
      </div>
    </header>
  );
}

// ── Hero ────────────────────────────────────────────────────────────────────

function Hero({ t, showImage }) {
  return (
    <section className="ps-hero" id="top" data-screen-label="Hero">
      <div className="ps-hero-shape" aria-hidden="true" />
      <Reveal className="ps-hero-text">
        <Eyebrow>{t.hero.eyebrow}</Eyebrow>
        <h1 className="ps-h1"><MarkerText text={t.hero.title} /></h1>
        <p className="ps-lede">{t.hero.sub}</p>
        <div className="ps-hero-cta">
          <Button kind="primary" as="a" href="#book">{t.hero.primary}</Button>
          <Button kind="ghost" as="a" href="#approach">{t.hero.secondary}</Button>
        </div>
      </Reveal>
      {showImage && (
        <Reveal className="ps-hero-media" delay={120}>
          <img
            className="ps-hero-photo"
            src="uploads/image.png"
            alt={t.hero.imageCaption}
            loading="eager"
          />
          <div className="ps-hero-media-caption">{t.hero.imageCaption}</div>
        </Reveal>
      )}
    </section>
  );
}

// ── About ───────────────────────────────────────────────────────────────────

function About({ t }) {
  return (
    <section className="ps-section" id="about" data-screen-label="About">
      <Reveal>
        <div className="ps-section-head">
          <Eyebrow>{t.about.eyebrow}</Eyebrow>
          <SectionTitle>{t.about.title}</SectionTitle>
        </div>
      </Reveal>
      <Reveal delay={120}>
        <div className="ps-about-grid">
          <div className="ps-about-body">
            {t.about.body.map((p, i) => <p key={i} className="ps-p">{p}</p>)}
          </div>
          <dl className="ps-credentials">
            {t.about.credentials.map((c, i) => (
              <div key={i} className="ps-cred-row">
                <dt>{c.k}</dt>
                <dd>{c.v}</dd>
              </div>
            ))}
          </dl>
        </div>
      </Reveal>
    </section>
  );
}

// ── Approach ────────────────────────────────────────────────────────────────

function Approach({ t }) {
  return (
    <section className="ps-section ps-section-soft" id="approach" data-screen-label="Approach">
      <Reveal>
        <div className="ps-section-head">
          <Eyebrow>{t.approach.eyebrow}</Eyebrow>
          <SectionTitle>{t.approach.title}</SectionTitle>
        </div>
      </Reveal>
      <Reveal delay={120}>
        <ol className="ps-approach-list stagger">
          {t.approach.points.map((p, i) => (
            <li key={i} className="ps-approach-item">
              <span className="ps-approach-num">{String(i + 1).padStart(2, "0")}</span>
              <div className="ps-approach-body">
                <h3 className="ps-h3"><MarkerText text={p.k} /></h3>
                <p className="ps-p">{p.v}</p>
              </div>
            </li>
          ))}
        </ol>
      </Reveal>
    </section>
  );
}

// ── Services ────────────────────────────────────────────────────────────────

function Services({ t, lang, onBook }) {
  return (
    <section className="ps-section" id="services" data-screen-label="Services">
      <Reveal>
        <div className="ps-section-head">
          <Eyebrow>{t.services.eyebrow}</Eyebrow>
          <SectionTitle>{t.services.title}</SectionTitle>
          <p className="ps-section-note">{t.services.currencyNote}</p>
        </div>
      </Reveal>
      <Reveal delay={120}>
        <div className="ps-services-grid stagger">
          {t.services.items.map((s) => (
            <article key={s.id} className="ps-service">
              <header className="ps-service-head">
                <h3 className="ps-h3">{s.name}</h3>
                <div className="ps-service-dur">{s.duration}</div>
              </header>
              <p className="ps-p ps-service-desc">{s.desc}</p>
              <footer className="ps-service-foot">
                <div className="ps-price">
                  <span className="ps-price-num">
                    {lang === "en" ? `$${s.price}` : `$${s.price.toLocaleString("es-MX")}`}
                  </span>
                  <span className="ps-price-unit">
                    {lang === "en" ? `${t.misc.usd} · ${t.misc.perSession}` : `${t.misc.mxn} · ${t.misc.perSession}`}
                  </span>
                </div>
                <button
                  type="button"
                  className="ps-btn ps-btn-ghost ps-btn-sm"
                  onClick={() => onBook(s.id)}
                >
                  {t.services.bookCta} →
                </button>
              </footer>
            </article>
          ))}
        </div>
      </Reveal>
    </section>
  );
}

// ── Contact ─────────────────────────────────────────────────────────────────

function Contact({ t }) {
  const [sent, setSent] = useState(false);
  const submit = (e) => {
    e.preventDefault();
    setSent(true);
  };
  return (
    <section className="ps-section" id="contact" data-screen-label="Contact">
      <Reveal>
        <div className="ps-section-head">
          <Eyebrow>{t.contact.eyebrow}</Eyebrow>
          <SectionTitle>{t.contact.title}</SectionTitle>
          <p className="ps-section-note">{t.contact.sub}</p>
        </div>
      </Reveal>
      <Reveal delay={120}>
        <div className="ps-contact-grid">
          {sent ? (
            <div className="ps-contact-sent">
              <p className="ps-p">{t.contact.sent}</p>
            </div>
          ) : (
            <form className="ps-contact-form" onSubmit={submit}>
              <label className="ps-field">
                <span>{t.contact.name}</span>
                <input type="text" required />
              </label>
              <label className="ps-field">
                <span>{t.contact.email}</span>
                <input type="email" required />
              </label>
              <label className="ps-field">
                <span>{t.contact.message}</span>
                <textarea rows="4" required></textarea>
              </label>
              <Button kind="primary" type="submit">{t.contact.send}</Button>
            </form>
          )}
          <aside className="ps-contact-aside">
            <div>
              <div className="ps-contact-label">{t.contact.hoursTitle}</div>
              <div className="ps-p">{t.contact.hoursMon} · {t.contact.hoursTime}</div>
              <div className="ps-p">{t.contact.hoursFri} · {t.contact.hoursFriTime}</div>
            </div>
            <div>
              <div className="ps-contact-label">{t.contact.addressTitle}</div>
              <div className="ps-p">{t.contact.address}</div>
            </div>
            <div>
              <div className="ps-contact-label">{t.contact.directTitle}</div>
              <div className="ps-p">ale@alepalomo.mx</div>
              <div className="ps-p">+52 984 000 0000</div>
            </div>
          </aside>
        </div>
      </Reveal>
    </section>
  );
}

// ── Footer ──────────────────────────────────────────────────────────────────

function Footer({ t }) {
  return (
    <footer className="ps-footer" data-screen-label="Footer">
      <div className="ps-footer-row">
        <div className="ps-footer-brand">
          <span className="ps-logo-mark ps-logo-mark-sm" aria-hidden="true" />
          <span>Ale Palomo</span>
        </div>
        <div className="ps-footer-tag">{t.footer.tagline}</div>
        <div className="ps-footer-links">
          <a href="#">{t.footer.links.privacy}</a>
          <a href="#">{t.footer.links.terms}</a>
        </div>
      </div>
      <div className="ps-footer-meta">
        <div>{t.footer.copyright}</div>
        <div className="ps-footer-notice">{t.footer.notice}</div>
      </div>
    </footer>
  );
}

// ── App ─────────────────────────────────────────────────────────────────────

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "bloom",
  "fonts": "editorial",
  "bookingPrimary": "pay",
  "headerLayout": "classic",
  "heroImage": true
}/*EDITMODE-END*/;

function App() {
  const [lang, setLang, t] = useLang();
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [bookingService, setBookingService] = useState(null);
  const bookingRef = useRef(null);

  useEffect(() => {
    const root = document.documentElement;
    const updateProgress = (scroll) => {
      root.style.setProperty("--scroll-y", scroll + "px");
      const max = document.documentElement.scrollHeight - window.innerHeight;
      root.style.setProperty("--scroll-progress", max > 0 ? (scroll / max).toFixed(4) : "0");
    };

    let lenisInstance = null;
    let cleanupFallback = null;

    if (typeof Lenis === "undefined") {
      // Fallback: native scroll listener so parallax still works without Lenis.
      const onScroll = () => updateProgress(window.scrollY);
      onScroll();
      window.addEventListener("scroll", onScroll, { passive: true });
      cleanupFallback = () => window.removeEventListener("scroll", onScroll);
    } else {
      const lenis = new Lenis({
        lerp: 0.13,
        smoothWheel: true,
        smoothTouch: false,
      });
      lenis.on("scroll", ({ scroll }) => updateProgress(scroll));
      let rafId;
      const raf = (time) => {
        lenis.raf(time);
        rafId = requestAnimationFrame(raf);
      };
      rafId = requestAnimationFrame(raf);
      lenisInstance = lenis;
      // Expose so the delegated anchor handler below can call scrollTo.
      window.__lenis = lenis;
      cleanupFallback = () => {
        cancelAnimationFrame(rafId);
        lenis.destroy();
        window.__lenis = null;
      };
    }

    // Intercept same-page anchor clicks and route through Lenis (or native
    // smooth scroll fallback) so navigation eases instead of teleporting.
    const onAnchorClick = (e) => {
      // Only handle primary clicks without modifier keys.
      if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
      const a = e.target.closest('a[href^="#"]');
      if (!a) return;
      const href = a.getAttribute("href");
      if (!href || href === "#") return;
      const target = document.querySelector(href);
      if (!target) return;
      e.preventDefault();
      const headerH = document.querySelector(".ps-header")?.offsetHeight || 0;
      const offset = -headerH - 12;
      if (lenisInstance) {
        lenisInstance.scrollTo(target, { offset, duration: 1.1 });
      } else {
        const y = target.getBoundingClientRect().top + window.scrollY + offset;
        window.scrollTo({ top: y, behavior: "smooth" });
      }
    };
    document.addEventListener("click", onAnchorClick);

    return () => {
      document.removeEventListener("click", onAnchorClick);
      if (cleanupFallback) cleanupFallback();
    };
  }, []);

  const goToBooking = (serviceId) => {
    if (serviceId) setBookingService(serviceId);
    requestAnimationFrame(() => {
      const el = document.getElementById("book");
      if (el) window.scrollTo({ top: el.offsetTop - 24, behavior: "smooth" });
    });
  };

  return (
    <>
      <ThemeStyle palette={tw.palette} fonts={tw.fonts} />
      <div className="ps-scroll-progress" aria-hidden="true" />
      <div className="ps-ambient" aria-hidden="true">
        <div className="ps-blob ps-blob-1" />
        <div className="ps-blob ps-blob-2" />
        <div className="ps-blob ps-blob-3" />
        <div className="ps-blob ps-blob-4" />
        <div className="ps-blob ps-blob-5" />
      </div>
      <div className="ps-shell" data-screen-label="Site">
        <Header lang={lang} setLang={setLang} t={t} layout={tw.headerLayout} onBook={() => goToBooking()} />
        <main>
          <Hero t={t} showImage={tw.heroImage} />
          <About t={t} />
          <Approach t={t} />
          <Services t={t} lang={lang} onBook={goToBooking} />
          <Booking
            t={t}
            lang={lang}
            primaryFlow={tw.bookingPrimary}
            preselectService={bookingService}
            ref={bookingRef}
          />
          <Contact t={t} />
        </main>
        <Footer t={t} />
      </div>

      <TweaksPanel title="Tweaks">
        <TweakSection label={lang === "en" ? "Theme" : "Tema"} />
        <TweakRadio
          label={lang === "en" ? "Palette" : "Paleta"}
          value={tw.palette}
          options={[
            { value: "bloom", label: "Bloom" },
            { value: "sage", label: "Sage" },
            { value: "sea", label: "Sea" },
          ]}
          onChange={(v) => setTweak("palette", v)}
        />
        <TweakRadio
          label={lang === "en" ? "Fonts" : "Tipografía"}
          value={tw.fonts}
          options={[
            { value: "editorial", label: "Editorial" },
            { value: "quiet", label: "Quiet" },
          ]}
          onChange={(v) => setTweak("fonts", v)}
        />

        <TweakSection label={lang === "en" ? "Layout" : "Diseño"} />
        <TweakRadio
          label={lang === "en" ? "Header" : "Encabezado"}
          value={tw.headerLayout}
          options={[
            { value: "classic", label: lang === "en" ? "Classic" : "Clásico" },
            { value: "centered", label: lang === "en" ? "Centered" : "Centrado" },
          ]}
          onChange={(v) => setTweak("headerLayout", v)}
        />
        <TweakToggle
          label={lang === "en" ? "Hero portrait" : "Retrato del hero"}
          value={tw.heroImage}
          onChange={(v) => setTweak("heroImage", v)}
        />

        <TweakSection label={lang === "en" ? "Booking" : "Agenda"} />
        <TweakRadio
          label={lang === "en" ? "Default flow" : "Flujo por defecto"}
          value={tw.bookingPrimary}
          options={[
            { value: "pay", label: lang === "en" ? "Pay now" : "Pagar" },
            { value: "code", label: lang === "en" ? "Use code" : "Código" },
          ]}
          onChange={(v) => setTweak("bookingPrimary", v)}
        />
      </TweaksPanel>
    </>
  );
}

window.App = App;
