/* ============================================================
   ПРИЛОЖЕНИЕ — маршрутизация, тема, состояние
   ============================================================ */

function useLocalState(key, initial) {
  const [v, setV] = useState(() => {
    try { return localStorage.getItem(key) ?? initial; } catch (e) { return initial; }
  });
  useEffect(() => { try { localStorage.setItem(key, v); } catch (e) {} }, [key, v]);
  return [v, setV];
}

/* читатель заметки блога */
function NoteReader({ note, onClose }) {
  const open = !!note;
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [open, onClose]);

  return (
    <div className={"lightbox" + (open ? " is-open" : "")} aria-hidden={!open}>
      <div className="lightbox__top">
        <span className="lightbox__counter">{note ? note.tag.toUpperCase() : ""}</span>
        <button className="lightbox__close" onClick={onClose}>Закрыть <Icon.close /></button>
      </div>
      <div className="lightbox__stage notereader" style={{ alignItems: "start", overflowY: "auto" }}>
        <div className="notereader__inner">
          <div className="notereader__spine" aria-hidden="true">
            <Coil count={28} />
          </div>
          <article className="notereader__sheet">
            {note && <>
              <div className="eyebrow" style={{ marginBottom: 18 }}>{note.date}</div>
              <h2 style={{ fontWeight: 300, fontSize: "clamp(2rem,5vw,3.2rem)", letterSpacing: "-0.03em", lineHeight: 1.02, margin: "0 0 28px" }}>{note.title}</h2>
              <div className="rule" style={{ marginBottom: 28 }} />
              {note.body.map((p, k) => (
                <p key={k} style={{ fontSize: 16, lineHeight: 1.75, color: "var(--fg)", opacity: 0.88, margin: "0 0 1.1em", maxWidth: "60ch" }}>{p}</p>
              ))}
            </>}
          </article>
        </div>
      </div>
    </div>
  );
}

const VALID = ["home", "photo", "art", "friends", "about", "blog", "new"];
function readHash() {
  const h = (location.hash || "").replace("#", "");
  return VALID.includes(h) ? h : "home";
}

function App() {
  const [theme, setTheme] = useLocalState("vm-theme", "dark");
  const [view, setView] = useLocalState("vm-view", "grid");
  const [mono, setMono] = useLocalState("vm-mono", "color");
  const [route, setRoute] = useState(readHash);
  const [menuOpen, setMenuOpen] = useState(false);
  const [pendingOpen, setPendingOpen] = useState(-1);
  const [note, setNote] = useState(null);

  /* контент из CMS: страница рисуется сразу на встроенных данных,
     а когда придёт ответ Sanity — перерисовывается свежим содержимым */
  const [rev, setRev] = useState(0);
  useEffect(() => {
    if (typeof loadContent !== "function") return;
    loadContent().then((ok) => { if (ok) setRev((r) => r + 1); });
  }, []);

  /* применяем тему */
  useEffect(() => { document.documentElement.setAttribute("data-theme", theme); }, [theme]);
  /* ч/б режим фотографий */
  useEffect(() => { document.documentElement.classList.toggle("mono-photos", mono === "mono"); }, [mono]);

  /* hash-роутинг */
  useEffect(() => {
    const onHash = () => { setRoute(readHash()); setPendingOpen(-1); window.scrollTo(0, 0); };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  const go = useCallback((r) => {
    setPendingOpen(-1);
    setMenuOpen(false);
    if (location.hash.replace("#", "") === r) { setRoute(r); window.scrollTo(0, 0); }
    else location.hash = r;
    window.scrollTo(0, 0);
  }, []);

  const openFromHome = useCallback((r, idx) => {
    setMenuOpen(false);
    setRoute(r);
    history.replaceState(null, "", "#" + r);
    setPendingOpen(idx);
    window.scrollTo(0, 0);
  }, []);

  const toggleTheme = () => setTheme((t) => (t === "dark" ? "light" : "dark"));

  /* новая версия главной — приходит со своей шапкой и меню,
     поэтому показываем её без общей обвязки сайта (иначе будет две шапки) */
  if (route === "new") {
    return <NewHome key={rev} go={go} onOpen={openFromHome} theme={theme} onToggle={toggleTheme} />;
  }

  let page;
  if (route === "photo") {
    page = <Gallery key={"photo-" + pendingOpen} id="photo" kicker="Архив · Фотография"
      title="Плёнка" lead="Серия «У стены» — портреты у городских стен. Средний формат 6×6, дневной свет, минимум обработки."
      items={PHOTO} view={view} onView={setView} mono={mono} onMono={setMono} initialIndex={pendingOpen} />;
  } else if (route === "art") {
    page = <Gallery key={"art-" + pendingOpen} id="art" kicker="Архив · Рисунок"
      title="Рисунок" lead="Этюды и работы на бумаге. Тушь, графит, акварель, уголь — ежедневная практика."
      items={ART} view={view} onView={setView} mono={mono} onMono={setMono} initialIndex={pendingOpen} />;
  } else if (route === "about") {
    page = <About />;
  } else if (route === "friends") {
    page = <Friends />;
  } else if (route === "blog") {
    page = <Blog onOpenNote={setNote} />;
  } else {
    page = <Home go={go} onOpen={openFromHome} />;
  }

  return (
    <>
      <Header route={route} go={go} theme={theme} onToggle={toggleTheme}
        menuOpen={menuOpen} onBurger={() => setMenuOpen((o) => !o)} />
      <MobileSheet open={menuOpen} route={route} go={go} onClose={() => setMenuOpen(false)} />
      <main key={rev}>{page}</main>
      <Footer go={go} />
      <NoteReader note={note} onClose={() => setNote(null)} />
    </>
  );
}

/* Gallery initialIndex поддержка: оборачиваем, чтобы стартовать lightbox */
const _Gallery = window.Gallery;
window.Gallery = function GalleryWithInitial(props) {
  const { initialIndex = -1, ...rest } = props;
  const [lb, setLb] = useState(initialIndex);
  const { id, kicker, title, lead, items, view, onView, mono, onMono } = rest;
  const hasPhotos = items.some((it) => it.src);
  return (
    <section className="gallery wrap page">
      <div className="gallery__head">
        <div>
          <div className="eyebrow" style={{ marginBottom: 16 }}>{kicker}</div>
          <h1 className="gallery__title">{title}</h1>
        </div>
        <p className="gallery__lead">{lead}</p>
      </div>
      <div className="gallery__bar">
        <span className="gallery__count">{String(items.length).padStart(2, "0")} работ</span>
        <div className="gallery__bar-tools">
          {hasPhotos && (
            <div className="viewtoggle" role="group" aria-label="Цвет фотографий">
              <button className={mono === "color" ? "is-active" : ""} onClick={() => onMono("color")} aria-pressed={mono === "color"}>Цвет</button>
              <button className={mono === "mono" ? "is-active" : ""} onClick={() => onMono("mono")} aria-pressed={mono === "mono"}>Ч·Б</button>
            </div>
          )}
          <div className="viewtoggle" role="group" aria-label="Вид галереи">
            <button className={view === "grid" ? "is-active" : ""} onClick={() => onView("grid")} aria-pressed={view === "grid"}>
              <Icon.grid /> Сетка
            </button>
            <button className={view === "list" ? "is-active" : ""} onClick={() => onView("list")} aria-pressed={view === "list"}>
              <Icon.list /> Список
            </button>
          </div>
        </div>
      </div>
      {view === "grid" ? <GridView items={items} onOpen={setLb} /> : <ListView items={items} onOpen={setLb} />}
      <Lightbox items={items} index={lb} onClose={() => setLb(-1)} onIndex={setLb} />
    </section>
  );
};

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