/* global React */
const { useEffect, useRef, useState } = React;

// =============================================================
// useReveal: IntersectionObserver hook to add `.in` to elements.
// Also observes the DOM for new `.reveal` nodes added later (e.g. when a
// section toggles between two mockups), otherwise late-mounted elements
// stay at opacity:0 forever.
// =============================================================
function useReveal() {
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          e.target.classList.add("in");
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.12 });
    const observe = (el) => {
      if (el.classList.contains("in")) return;
      io.observe(el);
    };
    document.querySelectorAll(".reveal").forEach(observe);
    const mo = new MutationObserver((muts) => {
      for (const m of muts) {
        m.addedNodes.forEach((n) => {
          if (n.nodeType !== 1) return;
          if (n.classList && n.classList.contains("reveal")) observe(n);
          n.querySelectorAll && n.querySelectorAll(".reveal").forEach(observe);
        });
      }
    });
    mo.observe(document.body, { childList: true, subtree: true });
    return () => { io.disconnect(); mo.disconnect(); };
  }, []);
}

// =============================================================
// detectOS
// =============================================================
function detectOS() {
  if (typeof navigator === "undefined") return "mac";
  const ua = navigator.userAgent || "";
  const platform = navigator.platform || "";
  if (/Mac|iPhone|iPad|iPod/.test(platform) || /Mac/.test(ua)) return "mac";
  if (/Win/.test(platform) || /Windows/.test(ua)) return "win";
  if (/Linux/.test(platform) || /Linux|X11/.test(ua)) return "linux";
  return "mac";
}

// =============================================================
// Brand mark
// =============================================================
function BrandMark({ size = 28 }) {
  return (
    <span style={{
      width: size, height: size,
      backgroundImage: "url(assets/icon_1024.png)",
      backgroundSize: "contain", backgroundRepeat: "no-repeat",
      backgroundPosition: "center",
      display: "inline-block",
      flexShrink: 0,
    }}/>
  );
}

// =============================================================
// Keycap
// =============================================================
function Keycap({ children, size = "md" }) {
  const sizes = {
    sm: { fs: 11, pad: "3px 6px", minW: 18, h: 20 },
    md: { fs: 13, pad: "5px 9px", minW: 24, h: 26 },
    lg: { fs: 16, pad: "8px 12px", minW: 32, h: 34 },
  };
  const s = sizes[size];
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      minWidth: s.minW, height: s.h, padding: s.pad,
      fontFamily: "var(--font-display)", fontWeight: 600, fontSize: s.fs,
      background: "linear-gradient(180deg, var(--bg-elev), transparent)",
      border: "1px solid var(--line-strong)",
      borderRadius: 8,
      boxShadow: "0 1px 0 rgba(255,255,255,0.04) inset, 0 2px 0 rgba(0,0,0,0.25), 0 4px 8px rgba(0,0,0,0.18)",
      color: "var(--fg)",
      letterSpacing: "0.02em",
    }}>{children}</span>
  );
}

// =============================================================
// Section header
// =============================================================
function Eyebrow({ children, color = "#38BDF8", num }) {
  return (
    <div style={{
      fontFamily: "var(--font-mono)", fontSize: 11,
      color, letterSpacing: "0.14em", textTransform: "uppercase",
      display: "inline-flex", alignItems: "center", gap: 10,
    }}>
      {num && (
        <span style={{
          color: "var(--fg-faint)", fontVariantNumeric: "tabular-nums",
          fontWeight: 500,
        }}>{String(num).padStart(2, "0")}</span>
      )}
      <span style={{ width: 16, height: 1, background: color, opacity: 0.6 }}/>
      {children}
    </div>
  );
}

function SectionTitle({ children, align = "left", maxWidth }) {
  return (
    <h2 className="reveal" style={{
      fontFamily: "var(--font-display)",
      fontSize: "clamp(32px, 4.5vw, 56px)",
      fontWeight: 700,
      letterSpacing: "-0.025em",
      lineHeight: 1.05,
      color: "var(--fg)",
      margin: 0,
      textAlign: align,
      maxWidth: maxWidth,
      marginInline: align === "center" ? "auto" : undefined,
      textWrap: "balance",
    }}>{children}</h2>
  );
}

function SectionLead({ children, align = "left", maxWidth = 560 }) {
  return (
    <p className="reveal" style={{
      fontSize: 18, lineHeight: 1.55,
      color: "var(--fg-muted)",
      margin: "20px 0 0",
      textAlign: align,
      maxWidth,
      marginInline: align === "center" ? "auto" : undefined,
      textWrap: "pretty",
    }}>{children}</p>
  );
}

// =============================================================
// Button
// =============================================================
function Button({ href = "#", primary, children, sub, icon, onClick }) {
  const [hover, setHover] = useState(false);
  return (
    <a href={href} onClick={onClick}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: "inline-flex", alignItems: "center", gap: 12,
        padding: "12px 20px", borderRadius: 10,
        background: primary
          ? (hover ? "var(--btn-primary-hover, rgba(255,255,255,0.92))" : "var(--btn-primary, white)")
          : (hover ? "var(--bg-elev)" : "transparent"),
        color: primary ? "var(--btn-primary-fg, #0A0A0A)" : "var(--fg)",
        border: primary ? "0" : "1px solid var(--line-strong)",
        textDecoration: "none",
        fontFamily: "var(--font-sans)",
        transition: "all 200ms cubic-bezier(0.2,0.8,0.2,1)",
        transform: hover ? "translateY(-1px)" : "translateY(0)",
        boxShadow: primary && hover ? "0 8px 24px rgba(255,255,255,0.15)" : "none",
        cursor: "pointer",
      }}>
      {icon}
      <span style={{ display: "inline-flex", flexDirection: "column", alignItems: "flex-start", gap: 1 }}>
        <span style={{ fontWeight: 600, fontSize: 14, lineHeight: 1.2 }}>{children}</span>
        {sub && <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, opacity: 0.55 }}>{sub}</span>}
      </span>
    </a>
  );
}

// =============================================================
// OS Logo (drawn in CSS for crispness)
// =============================================================
function OSLogo({ os, size = 16 }) {
  const fill = "currentColor";
  if (os === "mac") return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}><path d="M16.365 1.43c0 1.14-.466 2.196-1.227 2.96-.86.86-2.18 1.515-3.27 1.43-.13-1.14.43-2.32 1.18-3.06.85-.86 2.32-1.5 3.32-1.33zm3.39 17.07c-.66 1.51-.97 2.18-1.81 3.51-1.18 1.86-2.84 4.18-4.91 4.2-1.84.02-2.31-1.2-4.81-1.18-2.5.01-3.02 1.2-4.86 1.18-2.07-.02-3.65-2.11-4.83-3.97C-.51 18.5-.79 14.4 1.05 12.06 2.36 10.4 4.43 9.41 6.39 9.41c2 0 3.25 1.1 4.9 1.1 1.6 0 2.57-1.1 4.89-1.1 1.74 0 3.59.95 4.9 2.6-4.31 2.36-3.61 8.5-1.32 9.49z"/></svg>
  );
  if (os === "win") return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}><path d="M0 3.5L9.75 2.2v9.45H0V3.5zm10.95-1.45L24 0v11.65H10.95V2.05zM0 12.85h9.75V22.3L0 21V12.85zm10.95 0H24V24l-13.05-1.7v-9.45z"/></svg>
  );
  if (os === "linux") return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}><path d="M12.504 0c-.155 0-.315.008-.48.021-4.226.333-3.105 4.807-3.17 6.298-.076 1.092-.3 1.953-1.05 3.02-.885 1.051-2.127 2.75-2.716 4.521-.278.832-.41 1.684-.287 2.489-.45.418-.91 1.012-.86 1.715.057.823.84 1.066 1.587 1.305.749.239 1.55.439 1.83.999.173.346.151.857.214 1.382.063.524.171 1.069.475 1.466.494.541 1.124.6 1.74.575 1.063-.043 2.06-.516 2.732-.516.673 0 1.67.473 2.732.516.616.025 1.246-.034 1.74-.575.304-.397.412-.942.475-1.466.063-.525.04-1.036.214-1.382.28-.56 1.081-.76 1.83-.999.747-.239 1.53-.482 1.587-1.305.05-.703-.41-1.297-.86-1.715.123-.805-.009-1.657-.287-2.489-.589-1.771-1.831-3.47-2.716-4.521-.75-1.067-.974-1.928-1.05-3.02-.065-1.491 1.056-5.965-3.17-6.298a6.341 6.341 0 0 0-.48-.021z"/></svg>
  );
  return null;
}

// =============================================================
// Card
// =============================================================
function Card({ children, padding = 24, style = {} }) {
  return (
    <div style={{
      padding, borderRadius: 16,
      background: "linear-gradient(180deg, var(--bg-elev), transparent)",
      border: "1px solid var(--line)",
      ...style,
    }}>{children}</div>
  );
}

// =============================================================
// Code dot
// =============================================================
function CodeDot({ color }) {
  return <span style={{
    display: "inline-block", width: 8, height: 8, borderRadius: 99,
    background: color, boxShadow: `0 0 8px ${color}80`,
    flexShrink: 0,
  }}/>;
}

// =============================================================
// useGitHubStars: fetch live star count with localStorage cache
// =============================================================
function useGitHubStars(repo = "KonradDallaOrg/dimmy") {
  const [stars, setStars] = useState(null);
  useEffect(() => {
    const cacheKey = `gh-stars-${repo}`;
    const ttl = 60 * 60 * 1000; // 1h
    try {
      const cached = JSON.parse(localStorage.getItem(cacheKey) || "null");
      if (cached && Date.now() - cached.t < ttl && typeof cached.n === "number") {
        setStars(cached.n);
        return;
      }
    } catch (e) {}
    fetch(`https://api.github.com/repos/${repo}`)
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => {
        if (data && typeof data.stargazers_count === "number") {
          setStars(data.stargazers_count);
          try { localStorage.setItem(cacheKey, JSON.stringify({ n: data.stargazers_count, t: Date.now() })); } catch (e) {}
        }
      })
      .catch(() => {});
  }, [repo]);
  return stars;
}

function formatStars(n) {
  if (n == null) return null;
  if (n >= 10000) return `${Math.round(n / 1000)}k`;
  if (n >= 1000) return `${(n / 1000).toFixed(1).replace(/\.0$/, "")}k`;
  return String(n);
}

// =============================================================
// useLatestRelease: fetch latest release tag (e.g. "v1.4.0") from GitHub
// =============================================================
function useLatestRelease(repo = "KonradDallaOrg/dimmy") {
  const [tag, setTag] = useState(null);
  useEffect(() => {
    const cacheKey = `gh-release-${repo}`;
    const ttl = 60 * 60 * 1000;
    try {
      const cached = JSON.parse(localStorage.getItem(cacheKey) || "null");
      if (cached && Date.now() - cached.t < ttl && typeof cached.v === "string") {
        setTag(cached.v);
        return;
      }
    } catch (e) {}
    fetch(`https://api.github.com/repos/${repo}/releases/latest`)
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => {
        if (data && typeof data.tag_name === "string") {
          setTag(data.tag_name);
          try { localStorage.setItem(cacheKey, JSON.stringify({ v: data.tag_name, t: Date.now() })); } catch (e) {}
        }
      })
      .catch(() => {});
  }, [repo]);
  return tag;
}

window.Common = { useReveal, detectOS, BrandMark, Keycap, Eyebrow, SectionTitle, SectionLead, Button, OSLogo, Card, CodeDot, useGitHubStars, formatStars, useLatestRelease };
