// Sidebar / left rail with brand, live clock, italic statement, nav, contact.
// Renders persistently and is the spine of the editorial layout.

const { useEffect: _useEffect, useState: _useState, useMemo: _useMemo } = React;

const cityMap = {
  Sydney:    { tz: "Australia/Sydney",     code: "AU" },
  Melbourne: { tz: "Australia/Melbourne",  code: "AU" },
  Belgrade:  { tz: "Europe/Belgrade",      code: "RS" },
  Lisbon:    { tz: "Europe/Lisbon",        code: "PT" },
  London:    { tz: "Europe/London",        code: "UK" },
  NYC:       { tz: "America/New_York",     code: "US" },
  LA:        { tz: "America/Los_Angeles",  code: "US" },
  Tokyo:     { tz: "Asia/Tokyo",           code: "JP" },
  Dubai:     { tz: "Asia/Dubai",           code: "AE" },
  Paris:     { tz: "Europe/Paris",         code: "FR" },
  Bali:      { tz: "Asia/Makassar",        code: "ID" },
  Istanbul:  { tz: "Europe/Istanbul",      code: "TR" },
};

// ipapi returns the exact town you are standing in ("Adapazari"), which reads
// as noise. The IANA timezone always names the METRO ("Europe/Istanbul"), so
// that is the better label. Prefer a name already in cityMap so "America/
// New_York" shows as "NYC" like the picker does. Falls back to the raw tz
// segment, then to the town, so an unknown zone still shows something.
function metroFromTz(tz, townFallback) {
  const known = Object.entries(cityMap).find(([, cfg]) => cfg.tz === tz);
  if (known) return known[0];
  const seg = String(tz).split("/").pop();
  return seg ? seg.replace(/_/g, " ") : (townFallback || "");
}

// ONE geo lookup for the whole page. The rail and the Work headline both want
// "where is Drew right now", and each used to run its own fetch with its own
// idea of the answer, which is how the rail said ISTANBUL while the headline
// said Ankara on the same load. The promise is cached at module scope so a
// second consumer reuses the first one's result instead of spending another
// call against the free tier.
let geoPromise = null;
function fetchGeoOnce() {
  if (!geoPromise) {
    geoPromise = fetch("https://ipapi.co/json/")
      .then(r => r.json())
      .then(d => (d && d.timezone)
        ? { city: metroFromTz(d.timezone, d.city), code: d.country_code || "??", tz: d.timezone }
        : null)
      .catch(() => null); // offline or rate-limited: callers fall back
  }
  return geoPromise;
}

// Shared hook. sidebar.jsx loads before gallery.jsx, so window.useGeoCity is
// defined by the time the gallery mounts.
function useGeoCity() {
  const [geo, setGeo] = _useState(null);
  _useEffect(() => {
    let alive = true;
    fetchGeoOnce().then(g => { if (alive && g) setGeo(g); });
    return () => { alive = false; };
  }, []);
  return geo;
}
window.useGeoCity = useGeoCity;

function useClock({ format = "24h", seconds = true, tz, city, code }){
  const [now, setNow] = _useState(() => new Date());
  _useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);

  const day = now.toLocaleDateString("en-US", { weekday: "short", timeZone: tz });
  const timeOpts = { hour: "2-digit", minute: "2-digit", hour12: format === "12h", timeZone: tz };
  if(seconds) timeOpts.second = "2-digit";
  const time = now.toLocaleTimeString("en-GB", timeOpts).toUpperCase();

  return { day, time, code, city };
}

function Sidebar({ tweaks, setTweak, onNav, current, onOpenAdmin, slideIn = true }){
  const side = tweaks.menuSide === "right" ? "right" : "left";
  const [cityMenu, setCityMenu] = _useState(false);

  // Rail auto-minimizes once you scroll past the top region. Expands on hover,
  // on scroll-back-to-top, or when the user clicks the minimized tab to pin it.
  const [scrolled, setScrolled] = _useState(false);
  const [hover, setHover] = _useState(false);
  const [pinned, setPinned] = _useState(false); // user clicked the tab open
  const [isMobile, setIsMobile] = _useState(
    typeof window !== "undefined" && window.matchMedia("(max-width: 860px)").matches
  );
  const [mobileOpen, setMobileOpen] = _useState(false);

  const collapsed = !isMobile && scrolled && !hover && !pinned;

  _useEffect(() => {
    const THRESHOLD = 220; // px scrolled before the rail minimizes
    const onScroll = () => {
      const past = window.scrollY > THRESHOLD;
      setScrolled(past);
      if (!past) setPinned(false); // back at the top: forget the pin
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  _useEffect(() => {
    const mq = window.matchMedia("(max-width: 860px)");
    const on = () => { setIsMobile(mq.matches); if (!mq.matches) setMobileOpen(false); };
    mq.addEventListener("change", on);
    return () => mq.removeEventListener("change", on);
  }, []);

  // Mobile drawer: CSS (index.html, <=860px) owns the slide + width via a
  // .nav-open class on <html>. Doing it in CSS instead of inline style avoids
  // races with React re-renders and the intro's slideIn transform.
  _useEffect(() => {
    document.documentElement.classList.toggle("nav-open", mobileOpen);
    if (isMobile) document.body.style.overflow = mobileOpen ? "hidden" : "";
    return () => {
      document.documentElement.classList.remove("nav-open");
      document.body.style.overflow = "";
    };
  }, [isMobile, mobileOpen]);

  // Reflow <main> to reclaim the space (desktop only, via index.html rule).
  // Follows the minimized state so a hover/pin expand overlays content.
  _useEffect(() => {
    document.body.classList.toggle("rail-min", !isMobile && scrolled);
    return () => document.body.classList.remove("rail-min");
  }, [scrolled, isMobile]);

  // Auto-detect location from IP; falls back to manual clockCity tweak
  const geo = useGeoCity(); // { city, code, tz } — shared, one fetch per page
  const [manualCity, setManualCity] = _useState(null); // set when user picks from menu

  // Resolve what to display: manual pick > geo > tweaks default
  const resolved = _useMemo(() => {
    if (manualCity) {
      const cfg = cityMap[manualCity];
      return cfg ? { city: manualCity, code: cfg.code, tz: cfg.tz } : null;
    }
    if (geo) return geo;
    const fallback = cityMap[tweaks.clockCity] || cityMap.Sydney;
    return { city: tweaks.clockCity || "Sydney", code: fallback.code, tz: fallback.tz };
  }, [manualCity, geo, tweaks.clockCity]);

  const clock = useClock({ format: tweaks.clockFormat, seconds: tweaks.clockSeconds, ...resolved });

  const items = [
    { id: "work",      label: "Work" },
    { id: "about",     label: "About" },
    { id: "services",  label: "Services" },
    { id: "guides",    label: "Guides" },
    { id: "contact",   label: "Contact" },
  ];

  const cities = ["Sydney","Melbourne","NYC","LA","London","Paris","Lisbon","Istanbul","Belgrade","Tokyo","Dubai","Bali"];

  return (
    <>
    {/* Mobile: hamburger toggle (CSS shows it only <=860px) */}
    <button
      className="mobile-menu-btn"
      aria-label={mobileOpen ? "Close menu" : "Open menu"}
      aria-expanded={mobileOpen}
      onClick={() => setMobileOpen(v => !v)}
      style={{
        position:"fixed", top:14, [side]:14, zIndex:50,
        width:44, height:44, borderRadius:12,
        display:"none", alignItems:"center", justifyContent:"center",
        gap:4, flexDirection:"column",
        background:"var(--bg)", border:"1px solid var(--line-strong)",
      }}
    >
      {[0,1,2].map(i => (
        <span key={i} style={{
          width:18, height:1.5, background:"var(--fg)",
          transition:"transform .25s ease, opacity .2s ease",
          transform: mobileOpen
            ? (i === 0 ? "translateY(5.5px) rotate(45deg)" : i === 2 ? "translateY(-5.5px) rotate(-45deg)" : "none")
            : "none",
          opacity: mobileOpen && i === 1 ? 0 : 1,
        }}/>
      ))}
    </button>

    {/* Mobile drawer backdrop */}
    {isMobile && (
      <div onClick={() => setMobileOpen(false)} style={{
        position:"fixed", inset:0, zIndex:39,
        background:"rgba(10,10,9,.4)",
        opacity: mobileOpen ? 1 : 0,
        pointerEvents: mobileOpen ? "auto" : "none",
        transition:"opacity .3s ease",
      }}/>
    )}

    <aside
      className="sidebar-desktop"
      onMouseEnter={() => !isMobile && setHover(true)}
      onMouseLeave={() => !isMobile && setHover(false)}
      onClick={() => { if (!isMobile && collapsed) setPinned(true); }}
      style={{
        position:"fixed", top:0, [side]:0, height:"100vh",
        width: isMobile ? "min(320px, 82vw)" : (collapsed ? "56px" : "var(--rail-w)"),
        padding: collapsed ? "32px 8px 28px" : "32px 36px 28px", boxSizing:"border-box",
        display:"flex", flexDirection:"column",
        background:"var(--bg)",
        borderRight: side === "left" ? "1px solid var(--line)" : "none",
        borderLeft: side === "right" ? "1px solid var(--line)" : "none",
        overflow:"hidden",
        cursor: (!isMobile && collapsed) ? "pointer" : "default",
        zIndex:40,
        boxShadow: (isMobile && mobileOpen) ? "0 0 60px rgba(0,0,0,.25)" : "none",
        transform: slideIn ? "translateX(0)" : (side === "left" ? "translateX(-100%)" : "translateX(100%)"),
        transition: "transform .4s cubic-bezier(.2,.7,.2,1), width .4s cubic-bezier(.2,.7,.2,1), padding .4s ease",
        willChange:"transform, width",
      }}
    >
      {/* Minimized tab — the clickable affordance when collapsed */}
      <div aria-hidden={!collapsed} style={{
        position:"absolute", inset:0, zIndex:1,
        display:"flex", flexDirection:"column", alignItems:"center",
        paddingTop:34, gap:14,
        opacity: collapsed ? 1 : 0,
        pointerEvents:"none",
        transition:"opacity .25s ease",
      }}>
        <span className="display" style={{fontSize:18, fontWeight:600, letterSpacing:"-0.045em"}}>
          D<span style={{opacity:.35}}>_</span>N
        </span>
        <span title="Open menu" style={{
          display:"flex", flexDirection:"column", alignItems:"center", gap:4,
          padding:"8px 7px", borderRadius:9,
          border:"1px solid var(--line-strong)",
        }}>
          {[0,1,2].map(i => (
            <span key={i} style={{width:16, height:1.5, background:"var(--fg)", opacity:.65}}/>
          ))}
        </span>
      </div>

      {/* Full rail content. The panel widens over .4s; if the text fades in at
          the same time you watch it reflow and rewrap at 56px width first.
          So: hold it hidden, and only fade in after the width has settled
          (delay ~= width duration). Collapsing hides it at once — no delay on
          the way out. `visibility` keeps the mid-transition reflow off-screen
          instead of just transparent. */}
      <div style={{
        display:"flex", flexDirection:"column", flex:"1 1 auto", minHeight:0,
        opacity: collapsed ? 0 : 1,
        visibility: collapsed ? "hidden" : "visible",
        pointerEvents: collapsed ? "none" : "auto",
        transition: collapsed
          ? "opacity .12s ease, visibility 0s linear .12s"
          : "opacity .26s ease .42s, visibility 0s linear .42s",
      }}>
      {/* Pinned-open: small control to re-collapse (desktop, scrolled) */}
      {!isMobile && pinned && scrolled && (
        <button
          onClick={(e) => { e.stopPropagation(); setPinned(false); setHover(false); }}
          className="meta"
          style={{
            position:"absolute", top:8, [side === "left" ? "right" : "left"]:8, zIndex:2,
            width:26, height:26, borderRadius:8,
            display:"flex", alignItems:"center", justifyContent:"center",
            border:"1px solid var(--line-strong)", color:"var(--fg-soft)",
          }}
          title="Minimize menu"
        >{side === "left" ? "‹" : "›"}</button>
      )}
      {/* Clock row + clickable city */}
      <div className="meta" style={{display:"flex",gap:14,alignItems:"center",justifyContent:"space-between"}}>
        <span style={{fontVariantNumeric:"tabular-nums"}}>{clock.day} <span style={{opacity:.4,margin:"0 4px"}}>·</span> {clock.time}</span>
        <button
          onClick={() => setCityMenu(!cityMenu)}
          className="meta"
          style={{
            display:"inline-flex", alignItems:"center", gap:6,
            color:"var(--fg)", opacity:.85,
            padding:"3px 8px", borderRadius:999,
            background: cityMenu ? "color-mix(in oklch, var(--fg) 10%, transparent)" : "transparent",
            transition:"background .2s",
          }}
          title="Change city"
        >
          {clock.city} · {clock.code}
          <span style={{fontSize:9, opacity:.6}}>▾</span>
        </button>
      </div>

      {/* City menu */}
      {cityMenu && (
        <div style={{
          marginTop:10, padding:8,
          background:"color-mix(in oklch, var(--fg) 5%, transparent)",
          borderRadius:8,
          display:"grid", gridTemplateColumns:"1fr 1fr", gap:4,
        }}>
          <button onClick={() => { setManualCity(null); setCityMenu(false); }}
            className="meta"
            style={{
              textAlign:"left", padding:"6px 8px", borderRadius:6, gridColumn:"1/-1",
              color: !manualCity ? "var(--fg)" : "var(--fg-soft)",
              background: !manualCity ? "color-mix(in oklch, var(--fg) 8%, transparent)" : "transparent",
            }}>Auto-detect {geo ? `(${geo.city})` : ""}</button>
          {cities.map(c => (
            <button key={c} onClick={() => { setManualCity(c); setCityMenu(false); }}
              className="meta"
              style={{
                textAlign:"left", padding:"6px 8px", borderRadius:6,
                color: manualCity === c ? "var(--fg)" : "var(--fg-soft)",
                background: manualCity === c ? "color-mix(in oklch, var(--fg) 8%, transparent)" : "transparent",
              }}
            >{c}</button>
          ))}
        </div>
      )}

      {/* Brand */}
      <div style={{marginTop:44}}>
        <button onClick={() => { onNav && onNav("top"); setMobileOpen(false); }} style={{textAlign:"left"}}>
          <div className="display" style={{fontSize:36, lineHeight:1, letterSpacing:"-0.045em", fontWeight:600}}>
            Neros<span style={{opacity:.35, margin:"0 1px"}}>_</span>Studio<span style={{opacity:.5}}>.</span>
          </div>
          <div className="meta" style={{marginTop:14}}>Photographer / Retoucher</div>
        </button>
      </div>

      {/* Italic statement */}
      <p style={{
        marginTop:36, fontFamily:"var(--sans)", fontStyle:"italic",
        fontSize:14, lineHeight:1.5, color:"var(--fg-soft)", maxWidth:"24ch",
        margin:"36px 0 0",
      }}>
        Portraits, editorials<br/>and agency digitals.
      </p>

      {/* Nav */}
      <nav style={{marginTop:36, display:"flex", flexDirection:"column", gap:4}}>
        {items.map((it, i) => {
          const active = current === it.id;
          return (
            <button key={it.id}
              onClick={() => { onNav && onNav(it.id); setMobileOpen(false); }}
              style={{
                display:"flex", alignItems:"center", gap:14,
                padding:"6px 0",
                color:"var(--fg)",
                textAlign:"left",
                opacity: active ? 1 : .85,
                transition:"opacity .2s",
              }}
              onMouseEnter={(e) => e.currentTarget.style.opacity = 1}
              onMouseLeave={(e) => e.currentTarget.style.opacity = active ? 1 : .85}
            >
              <span className="meta" style={{width:22, textAlign:"left", color:"var(--fg-faint)"}}>
                {String(i+1).padStart(2,"0")}
              </span>
              <span style={{
                fontFamily:"var(--sans)", fontSize:18, fontWeight:500, letterSpacing:"-0.02em",
              }}>{it.label}</span>
              <span style={{
                marginLeft:"auto",
                transition:"transform .35s ease, opacity .35s ease",
                transform: active ? "translateX(0)" : "translateX(-6px)",
                opacity: active ? 1 : 0,
                fontSize:13,
              }}>—</span>
            </button>
          );
        })}
      </nav>

      <div style={{marginTop:"auto", display:"flex", flexDirection:"column", gap:18}}>
        {/* Status pill */}
        <div className="meta" style={{display:"flex",alignItems:"center",gap:8,color:"var(--fg-soft)"}}>
          <span className="dot blink" style={{width:7,height:7,borderRadius:999,background:"var(--film-olive)"}}/>
          <span>Booking · Summer '26</span>
        </div>
      </div>
      </div>
    </aside>
    </>
  );
}

Object.assign(window, { Sidebar, useClock });
