// Jai Mahal Audio Tour — shared utility components
// Brand mark (logo), Ornamental rule, Chapter chip, ImageCard

const { useEffect, useRef, useState } = React;

// ─── Brand mark (logo SVG wrapper) ──────────────────────────────────
function BrandMark({ size = 22, mono = false, color }) {
  // We use the user-supplied PNG logo. mono=true shows just the lockup wordmark glyph.
  return (
    <img
      src="assets/logo.png"
      alt="Jai Mahal Palace, Jaipur"
      style={{
        height: size,
        width: "auto",
        opacity: mono ? 0.85 : 1,
        filter: color ? `brightness(0) saturate(100%) ${color}` : "none",
        display: "block",
      }}
    />
  );
}

// Compact logo for header use — shows the full mark (crest + wordmark or crest-only).
// We use object-fit:contain to ensure both the elephants AND the arches are visible
// without cropping.
function BrandCrest({ size = 28, opacity = 1, crestOnly = true }) {
  // The source PNG is 1149 × 639. The crest occupies roughly the top 57% (380px wide).
  // For "crestOnly" we crop the bottom wordmark away with a clip-path; for the full
  // lockup we just show the whole thing.
  if (!crestOnly) {
    return (
      <img
        src="assets/logo.png"
        alt="Jai Mahal Palace, Jaipur"
        style={{
          height: size,
          width: "auto",
          opacity,
          display: "block",
        }}
      />
    );
  }
  // Crest only — show the icon portion (top 57% of the image).
  // We render at full width then mask off the lower wordmark band.
  const native = { w: 1149, h: 639 };
  const crestH = 360;            // crest extends from y=0 to ~y=360 in native px
  const crestAspect = native.w / crestH;  // ≈ 3.19, but the crest itself is narrow & centered
  // Easiest reliable approach: use background-image with size set so the crest fits.
  return (
    <div
      role="img"
      aria-label="Jai Mahal Palace crest"
      style={{
        width: size,
        height: size,
        backgroundImage: `url(assets/logo.png)`,
        // Scale the image so its width = size * (1149 / 380) ≈ size * 3.02 (the crest
        // is ~380 native px wide and centered). At this scale the crest fits in `size`.
        backgroundSize: `${size * 3.0}px auto`,
        backgroundPosition: "center top",
        backgroundRepeat: "no-repeat",
        opacity,
      }}
    />
  );
}

// ─── Ornamental hairline ───────────────────────────────────────────
function Rule({ variant = "diamond", color = "var(--gold)", width = 100 }) {
  if (variant === "plain") {
    return <div style={{ width, height: 1, background: color, opacity: 0.45 }} />;
  }
  // diamond: short line — diamond — short line
  return (
    <div style={{ display: "inline-flex", alignItems: "center", gap: 8, color }}>
      <span style={{ display: "block", width: width / 2 - 8, height: 1, background: "currentColor", opacity: 0.4 }} />
      <Icon.Diamond size={6} />
      <span style={{ display: "block", width: width / 2 - 8, height: 1, background: "currentColor", opacity: 0.4 }} />
    </div>
  );
}

// ─── Eyebrow label (small caps, gold) ───────────────────────────────
function Eyebrow({ children, color = "var(--gold-dark)", spacing = 3 }) {
  return (
    <span
      style={{
        fontFamily: "var(--font-sans)",
        fontSize: 11,
        fontWeight: 500,
        letterSpacing: spacing,
        textTransform: "uppercase",
        color,
        display: "inline-block",
      }}
    >
      {children}
    </span>
  );
}

// ─── Horizontal swipeable gallery ───────────────────────────────────
function Gallery({ images, aspect = "4/5", showCaption = true }) {
  const ref = useRef(null);
  const [idx, setIdx] = useState(0);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onScroll = () => {
      const w = el.clientWidth;
      setIdx(Math.round(el.scrollLeft / w));
    };
    el.addEventListener("scroll", onScroll, { passive: true });
    return () => el.removeEventListener("scroll", onScroll);
  }, []);

  return (
    <div>
      <div
        ref={ref}
        className="gallery-scroll"
        style={{
          display: "flex",
          overflowX: "auto",
          scrollSnapType: "x mandatory",
          gap: 14,
          padding: "0 22px",
          margin: "0 -22px",
          scrollbarWidth: "none",
        }}
      >
        {images.map((img, i) => (
          <figure
            key={i}
            style={{
              flex: "0 0 78%",
              scrollSnapAlign: "center",
              margin: 0,
              display: "flex",
              flexDirection: "column",
              gap: 10,
            }}
          >
            <div
              style={{
                aspectRatio: aspect,
                background: `url(${img.src}) center/cover no-repeat var(--ink-faint)`,
                border: "1px solid var(--border)",
              }}
            />
            {showCaption && (
              <figcaption
                style={{
                  fontFamily: "var(--font-serif)",
                  fontStyle: "italic",
                  fontWeight: 400,
                  fontSize: 13,
                  lineHeight: 1.45,
                  color: "var(--ink-soft)",
                  paddingRight: 8,
                }}
              >
                {img.caption}
              </figcaption>
            )}
          </figure>
        ))}
      </div>
      {/* Dots */}
      <div style={{ display: "flex", gap: 6, justifyContent: "center", marginTop: 14 }}>
        {images.map((_, i) => (
          <span
            key={i}
            style={{
              width: i === idx ? 18 : 5,
              height: 5,
              borderRadius: 3,
              background: i === idx ? "var(--gold-dark)" : "var(--ink-faint-2)",
              transition: "width .25s, background .25s",
            }}
          />
        ))}
      </div>
    </div>
  );
}

// ─── Section header w/ ornamental rule ──────────────────────────────
function SectionHead({ eyebrow, title }) {
  return (
    <div style={{ textAlign: "center", padding: "0 24px 18px" }}>
      <Eyebrow>{eyebrow}</Eyebrow>
      <h2
        style={{
          fontFamily: "var(--font-serif)",
          fontWeight: 400,
          fontStyle: "italic",
          fontSize: 26,
          lineHeight: 1.15,
          margin: "8px 0 14px",
          color: "var(--ink)",
          textWrap: "pretty",
        }}
      >
        {title}
      </h2>
      <Rule width={70} />
    </div>
  );
}

// ─── Primary button ────────────────────────────────────────────────
function PrimaryBtn({ children, onClick, full = true, dark = true }) {
  return (
    <button
      onClick={onClick}
      style={{
        width: full ? "100%" : "auto",
        background: dark ? "var(--ink)" : "var(--gold-dark)",
        color: dark ? "var(--cream)" : "white",
        border: "none",
        padding: "16px 22px",
        fontFamily: "var(--font-sans)",
        fontSize: 12,
        fontWeight: 500,
        letterSpacing: 2.5,
        textTransform: "uppercase",
        cursor: "pointer",
        display: "inline-flex",
        alignItems: "center",
        justifyContent: "center",
        gap: 10,
        borderRadius: 0,
      }}
    >
      {children}
    </button>
  );
}

// ─── Ghost button ──────────────────────────────────────────────────
function GhostBtn({ children, onClick, full = true }) {
  return (
    <button
      onClick={onClick}
      style={{
        width: full ? "100%" : "auto",
        background: "transparent",
        color: "var(--ink)",
        border: "1px solid var(--ink)",
        padding: "15px 22px",
        fontFamily: "var(--font-sans)",
        fontSize: 12,
        fontWeight: 500,
        letterSpacing: 2.5,
        textTransform: "uppercase",
        cursor: "pointer",
        display: "inline-flex",
        alignItems: "center",
        justifyContent: "center",
        gap: 10,
        borderRadius: 0,
      }}
    >
      {children}
    </button>
  );
}

Object.assign(window, { BrandMark, BrandCrest, Rule, Eyebrow, Gallery, SectionHead, PrimaryBtn, GhostBtn, AutoCarousel });

// ─── Auto-cycling photo carousel ────────────────────────────────────
// Crossfades through `images` every `interval` ms. Pure CSS opacity transitions.
// Exposes index via onChange callback for caption sync.
function AutoCarousel({ images, interval = 4500, fade = 1000, paused = false, onIndexChange, index = null, fit = "cover" }) {
  // Controlled mode: when `index` is supplied, the parent drives which image
  // shows (e.g. synced to an audio timeline). Otherwise auto-advance on a timer.
  const controlled = index != null;
  const [autoIdx, setAutoIdx] = useState(0);

  useEffect(() => {
    if (controlled || paused || images.length <= 1) return;
    const t = setInterval(() => {
      setAutoIdx((i) => (i + 1) % images.length);
    }, interval);
    return () => clearInterval(t);
  }, [controlled, paused, images.length, interval]);

  const idx = controlled ? Math.max(0, Math.min(images.length - 1, index)) : autoIdx;

  useEffect(() => {
    onIndexChange && onIndexChange(idx);
  }, [idx]);

  return (
    <div style={{ position: "absolute", inset: 0, overflow: "hidden", background: "#0d0906" }}>
      {images.map((img, i) => {
        const src = typeof img === "string" ? img : img.src;
        const pos = typeof img === "string" ? "center" : img.pos || "center";
        return (
          <div
            key={i}
            style={{
              position: "absolute",
              inset: 0,
              opacity: i === idx ? 1 : 0,
              transition: `opacity ${fade}ms ease`,
              willChange: "opacity",
            }}
          >
            {/* For "contain" fit, a blurred backdrop fills the frame ambiently so
                low-resolution images don't pixelate by being upscaled. Not needed
                for "cover" (full-bleed) where the image already fills the frame. */}
            {fit === "contain" && (
              <div
                style={{
                  position: "absolute",
                  inset: 0,
                  backgroundImage: `url(${src})`,
                  backgroundSize: "cover",
                  backgroundPosition: pos,
                  filter: "blur(28px) brightness(0.6)",
                  transform: "scale(1.15)",
                }}
              />
            )}
            <img
              src={src}
              alt=""
              style={{
                position: "absolute",
                inset: 0,
                width: "100%",
                height: "100%",
                objectFit: fit,
                objectPosition: pos,
              }}
            />
          </div>
        );
      })}
    </div>
  );
}

// ─── Language toggle (Globe + dropdown) ─────────────────────────────
// variant "dark" for image/overlay backgrounds, "light" for cream headers.
function LangToggle({ lang, setLang, variant = "light" }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("pointerdown", onDoc);
    return () => document.removeEventListener("pointerdown", onDoc);
  }, [open]);

  const dark = variant === "dark";
  const fg = dark ? "rgba(255,255,255,0.92)" : "var(--ink)";
  const border = dark ? "rgba(255,255,255,0.35)" : "var(--gold-dark)";
  const label = lang === "hi" ? "हिं" : "EN";
  const options = [
    { code: "en", label: "English" },
    { code: "hi", label: "हिंदी" },
  ];

  return (
    <div ref={ref} style={{ position: "relative", flexShrink: 0 }}>
      <button
        onClick={() => setOpen((o) => !o)}
        aria-label="Choose language"
        style={{
          display: "flex",
          alignItems: "center",
          gap: 5,
          background: dark ? "rgba(0,0,0,0.28)" : "transparent",
          border: `1px solid ${border}`,
          color: fg,
          borderRadius: 20,
          padding: "6px 10px",
          cursor: "pointer",
          fontFamily: "var(--font-sans)",
          fontSize: 11,
          fontWeight: 600,
          letterSpacing: 0.5,
          backdropFilter: dark ? "blur(4px)" : "none",
        }}
      >
        <Icon.Globe size={15} />
        <span>{label}</span>
        <Icon.ChevronDown size={12} />
      </button>

      {open && (
        <div
          style={{
            position: "absolute",
            top: "calc(100% + 6px)",
            right: 0,
            background: "var(--cream)",
            border: "1px solid var(--border)",
            borderRadius: 10,
            boxShadow: "0 10px 30px rgba(34,23,16,0.28)",
            overflow: "hidden",
            zIndex: 50,
            minWidth: 130,
          }}
        >
          {options.map((o) => {
            const active = o.code === lang;
            return (
              <button
                key={o.code}
                onClick={() => { setLang(o.code); setOpen(false); }}
                style={{
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "space-between",
                  width: "100%",
                  background: active ? "var(--cream-2)" : "transparent",
                  border: "none",
                  borderBottom: o.code === "en" ? "1px solid var(--border)" : "none",
                  color: "var(--ink)",
                  cursor: "pointer",
                  padding: "11px 14px",
                  fontFamily: "var(--font-sans)",
                  fontSize: 13,
                  fontWeight: active ? 700 : 500,
                  textAlign: "left",
                }}
              >
                <span>{o.label}</span>
                {active && <span style={{ color: "var(--gold-dark)" }}>✓</span>}
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { LangToggle });
