// Valicen — app shell: client-side router, theme, and Tweaks.

// ┌──────────────────────────────────────────────────────────────┐
// │  COMING-SOON SWITCH                                           │
// │  true  = public visitors see the splash page                 │
// │  false = full site is live for everyone                      │
// │  Flip this single value when you're ready to launch.         │
// │                                                              │
// │  WHILE true, the full site is still reachable three ways:    │
// │   1. Here in the Claude designer / preview (auto-detected).  │
// │   2. Via the secret PREVIEW LINK below — share it with       │
// │      anyone you want to show the work-in-progress to:        │
// │         https://YOURDOMAIN/?preview=valicen-preview-2026     │
// │      Their browser remembers it, so they can click around    │
// │      freely afterward. To revoke on a device, visit          │
// │         https://YOURDOMAIN/?preview=off                      │
// │   3. (Everyone else just sees the splash.)                   │
// └──────────────────────────────────────────────────────────────┘
const COMING_SOON = true;

// Secret token for the shareable preview link. Change this string to rotate
// the link (anyone using the old link is locked back out to the splash).
const PREVIEW_TOKEN = "valicen-preview-2026";
const PREVIEW_STORE_KEY = "valicen_preview_ok";

// True only in the Claude editing/preview environment (embedded in an iframe,
// or on the sandbox/localhost host) — NOT on your deployed public domain.
// Lets you keep editing the real site while the splash stays live for visitors.
function isEditingEnv() {
  if (typeof window === "undefined") return false;
  try {
    const host = window.location.hostname;
    const sandbox = /claudeusercontent\.com$/.test(host) || /\.claude\.ai$/.test(host);
    const local = host === "localhost" || host === "127.0.0.1" || host === "";
    const embedded = window.self !== window.top; // designer preview runs in an iframe
    return sandbox || local || embedded;
  } catch (e) {
    // Cross-origin access to window.top throws → we're embedded → editing env.
    return true;
  }
}

// Has this visitor unlocked the preview via the secret link? Reads the
// ?preview= query param (granting + persisting access, or revoking it with
// ?preview=off), then falls back to the remembered grant in localStorage.
function hasPreviewAccess() {
  if (typeof window === "undefined") return false;
  try {
    const params = new URLSearchParams(window.location.search);
    if (params.has("preview")) {
      const val = params.get("preview");
      if (val === "off") { localStorage.removeItem(PREVIEW_STORE_KEY); return false; }
      if (val === PREVIEW_TOKEN) { localStorage.setItem(PREVIEW_STORE_KEY, "1"); return true; }
    }
    return localStorage.getItem(PREVIEW_STORE_KEY) === "1";
  } catch (e) {
    return false;
  }
}

const SHOW_SITE = !COMING_SOON || isEditingEnv() || hasPreviewAccess();

// ---- Hash routing helpers ----
const PAGE_IDS = ["home", "services", "about", "work", "contact", "privacy", "terms", "downloads", "commitments", "samples"];
function pageFromHash() {
  const h = (window.location.hash || "").replace(/^#\/?/, "");
  return PAGE_IDS.includes(h) ? h : "home";
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "dark": false,
  "heroDir": "A",
  "sectionOrder": ["services", "process", "proof", "testimonials"]
}/*EDITMODE-END*/;

// Custom panel control: reorder the home page content sections.
function SectionOrderControl({ order, onChange }) {
  const labels = { services: "Services", process: "How we work", proof: "Proof strip", testimonials: "Testimonials" };
  const move = (i, dir) => {
    const j = i + dir;
    if (j < 0 || j >= order.length) return;
    const next = [...order];
    [next[i], next[j]] = [next[j], next[i]];
    onChange(next);
  };
  const rowStyle = { display: "flex", alignItems: "center", gap: 6, background: "rgba(255,255,255,.6)", border: ".5px solid rgba(0,0,0,.1)", borderRadius: 7, padding: "4px 5px 4px 9px" };
  const arrow = { height: 20, padding: "0 7px", lineHeight: 1 };
  return (
    <div className="twk-row">
      <div className="twk-lbl"><span>Home section order</span></div>
      <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
        {order.map((k, i) => (
          <div key={k} style={rowStyle}>
            <span style={{ flex: 1, fontWeight: 500 }}>{i + 1}. {labels[k]}</span>
            <button className="twk-btn secondary" style={arrow} disabled={i === 0} onClick={() => move(i, -1)}>↑</button>
            <button className="twk-btn secondary" style={arrow} disabled={i === order.length - 1} onClick={() => move(i, 1)}>↓</button>
          </div>
        ))}
      </div>
    </div>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [page, setPage] = React.useState(pageFromHash);

  // Hash routing: back/forward buttons and deep links (#services, #contact…)
  // work like real pages. The splash gate and ?preview token live in the query
  // string, so they are unaffected by hash changes.
  React.useEffect(() => {
    const onHash = () => { setPage(pageFromHash()); window.scrollTo(0, 0); };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  // Re-render lucide icons after every paint (handles route + theme changes).
  React.useEffect(() => { window.lucide && lucide.createIcons(); });

  // Apply theme to <html> so tokens cascade everywhere.
  React.useEffect(() => {
    document.documentElement.setAttribute("data-theme", t.dark ? "dark" : "light");
  }, [t.dark]);

  // Coming-soon gate: real visitors see the splash while COMING_SOON is true;
  // the editing/preview environment always shows the full site so you can build it.
  if (!SHOW_SITE) return <ComingSoon />;

  const go = React.useCallback((id) => {
    if (pageFromHash() !== id) {
      window.location.hash = id; // hashchange listener updates state + scroll
    } else {
      setPage(id);
      window.scrollTo({ top: 0, left: 0, behavior: "auto" });
    }
  }, []);

  const toggleTheme = React.useCallback(() => setTweak("dark", !t.dark), [t.dark, setTweak]);

  let view;
  if (page === "services") view = <ServicesPage go={go} />;
  else if (page === "about") view = <AboutPage go={go} />;
  else if (page === "work") view = <WorkPage go={go} />;
  else if (page === "contact") view = <ContactPage />;
  else if (page === "privacy") view = <PrivacyPage go={go} />;
  else if (page === "terms") view = <TermsPage go={go} />;
  else if (page === "downloads") view = <DownloadsPage go={go} />;
  else if (page === "commitments") view = <CommitmentsPage go={go} />;
  else if (page === "samples") view = <SamplesPage go={go} />;
  else view = <HomePage go={go} heroDir={t.heroDir} order={t.sectionOrder} />;

  return (
    <React.Fragment>
      <SiteHeader page={page} go={go} theme={t.dark ? "dark" : "light"} toggleTheme={toggleTheme} />
      {/* key forces remount so the page-enter animation + reveal observers refire */}
      <div key={page}>{view}</div>
      <SiteFooter go={go} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Appearance" />
        <TweakToggle label="Dark mode" value={t.dark} onChange={(v) => setTweak("dark", v)} />
        <TweakSection label="Homepage hero" />
        <TweakRadio label="Direction" value={t.heroDir}
          options={[{ value: "A", label: "Split" }, { value: "B", label: "Immersive" }, { value: "C", label: "Editorial" }]}
          onChange={(v) => setTweak("heroDir", v)} />
        <TweakSection label="Homepage layout" />
        <SectionOrderControl order={t.sectionOrder} onChange={(v) => setTweak("sectionOrder", v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
