/* App.jsx — root, view routing, search wiring. */

const DEFAULT_TITLE = "Writing — Spencer Voorhees";
const DEFAULT_DESC  = "Notes from the field — essays on systems design, engineering practice, and the quieter parts of doing technical work.";
const BASE_URL      = "https://blog.spencervoorhees.com";

function updateMeta(title, desc, url) {
  document.title = title;
  const set = (sel, val) => { const el = document.querySelector(sel); if (el) el.setAttribute("content", val); };
  set('meta[name="description"]', desc);
  set('meta[property="og:title"]', title);
  set('meta[property="og:description"]', desc);
  set('meta[property="og:url"]', url);
  set('meta[name="twitter:title"]', title);
  set('meta[name="twitter:description"]', desc);
}

function App() {
  const [dark, setDark] = React.useState(true);
  const [view, setView] = React.useState({ name: "index" });
  const [activeTag, setActiveTag] = React.useState(null);
  const [searchOpen, setSearchOpen] = React.useState(false);
  const [postsReady, setPostsReady] = React.useState(false);
  const [loadError, setLoadError] = React.useState(null);

  // Load posts from Sanity on mount, then honour ?post=slug deep links
  React.useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const deepPost = params.get("post");
    window.loadPosts()
      .then(posts => {
        window.BLOG_POSTS = posts;
        window.BLOG_TAGS = window.computeTags(posts);
        setPostsReady(true);
        if (deepPost) {
          const post = posts.find(p => p.id === deepPost);
          if (post) {
            updateMeta(post.title + " — Spencer Voorhees", post.summary, BASE_URL + "?post=" + deepPost);
            setView({ name: "post", id: deepPost });
          }
        }
      })
      .catch(err => {
        console.error("Failed to load posts:", err);
        setLoadError(err.message);
      });
  }, []);

  function go(target, opts = {}) {
    window.scrollTo(0, 0);
    if (target === "index") {
      updateMeta(DEFAULT_TITLE, DEFAULT_DESC, BASE_URL);
      window.history.pushState({}, "", window.location.pathname);
      setView({ name: "index" });
    } else if (target === "now") {
      updateMeta("Now — Spencer Voorhees", "What I'm doing now.", BASE_URL + "?page=now");
      window.history.pushState({}, "", "?page=now");
      setView({ name: "now" });
    } else if (target === "colophon") {
      updateMeta("Colophon — Spencer Voorhees", "How this site is made.", BASE_URL + "?page=colophon");
      window.history.pushState({}, "", "?page=colophon");
      setView({ name: "colophon" });
    } else if (target === "post") {
      const post = window.BLOG_POSTS && window.BLOG_POSTS.find(p => p.id === opts.id);
      if (post) updateMeta(post.title + " — Spencer Voorhees", post.summary, BASE_URL + "?post=" + opts.id);
      window.history.pushState({}, "", "?post=" + opts.id);
      setView({ name: "post", id: opts.id });
    }
  }

  // Browser back/forward button support
  React.useEffect(() => {
    function onPop() {
      const params = new URLSearchParams(window.location.search);
      const postSlug = params.get("post");
      const page = params.get("page");
      if (postSlug && window.BLOG_POSTS) {
        const post = window.BLOG_POSTS.find(p => p.id === postSlug);
        if (post) {
          updateMeta(post.title + " — Spencer Voorhees", post.summary, BASE_URL + "?post=" + postSlug);
          setView({ name: "post", id: postSlug });
        } else {
          setView({ name: "index" });
        }
      } else if (page === "now") {
        updateMeta("Now — Spencer Voorhees", "What I'm doing now.", BASE_URL + "?page=now");
        setView({ name: "now" });
      } else if (page === "colophon") {
        updateMeta("Colophon — Spencer Voorhees", "How this site is made.", BASE_URL + "?page=colophon");
        setView({ name: "colophon" });
      } else {
        updateMeta(DEFAULT_TITLE, DEFAULT_DESC, BASE_URL);
        setView({ name: "index" });
      }
      window.scrollTo(0, 0);
    }
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, []);

  React.useEffect(() => { window.lucide && window.lucide.createIcons(); });

  React.useEffect(() => {
    const html = document.documentElement;
    html.dataset.theme = dark ? "dark" : "light";
    html.setAttribute("data-density", "regular");
    html.setAttribute("data-accent", "blue");
  }, [dark]);

  React.useEffect(() => {
    function onKey(e) {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setSearchOpen(true);
      } else if (e.key === "/" && !searchOpen && document.activeElement === document.body) {
        e.preventDefault();
        setSearchOpen(true);
      }
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [searchOpen]);

  const currentNav = view.name === "now" ? "now" : "index";

  let body;
  if (!postsReady && view.name !== "now" && view.name !== "colophon") {
    body = loadError
      ? <LoadingError message={loadError} />
      : <LoadingSpinner />;
  } else if (view.name === "index") {
    body = (
      <window.BlogIndex
        onOpenPost={(id) => go("post", { id })}
        activeTag={activeTag}
        onSetTag={setActiveTag}
        density="comfortable"
      />
    );
  } else if (view.name === "post") {
    body = (
      <window.BlogPost
        postId={view.id}
        onBack={() => go("index")}
        onOpenPost={(id) => go("post", { id })}
        readingWidth={720}
      />
    );
  } else if (view.name === "now") {
    body = <window.NowPage onBack={() => go("index")} />;
  } else if (view.name === "colophon") {
    body = <window.ColophonPage onBack={() => go("index")} />;
  }

  return (
    <React.Fragment>
      <window.BlogTopNav
        dark={dark}
        onToggleTheme={() => setDark(d => !d)}
        onNavigate={(t) => go(t)}
        current={currentNav}
        onOpenSearch={() => setSearchOpen(true)}
      />
      {body}
      <window.SiteFooter onNavigate={(t) => go(t)} />
      <window.SearchOverlay
        open={searchOpen}
        onClose={() => setSearchOpen(false)}
        onOpenPost={(id) => { go("post", { id }); setSearchOpen(false); }}
      />
    </React.Fragment>
  );
}

function LoadingSpinner() {
  return (
    <main style={{ maxWidth: 880, margin: "0 auto", padding: "120px max(20px, 5vw)" }}>
      <div style={{
        fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--fg-quaternary)",
        letterSpacing: "0.08em", textTransform: "uppercase",
      }}>
        Loading posts…
      </div>
    </main>
  );
}

function LoadingError({ message }) {
  return (
    <main style={{ maxWidth: 880, margin: "0 auto", padding: "120px max(20px, 5vw)" }}>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--red-500)" }}>
        Failed to load posts: {message}
      </div>
    </main>
  );
}

window.App = App;
