// app.jsx — root + routing + tweaks wiring

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": ["#22d3c4", "#050505", "#f4f4f5"],
  "markaloudTreatment": "spotlight",
  "motion": "lively",
  "density": "regular",
  "displayFont": "Manrope",
  "showGrain": true
}/*EDITMODE-END*/;

const PALETTES = {
  "Lab teal":   ["#22d3c4", "#050505", "#f4f4f5"],
  "Phosphor":   ["#5eead4", "#050608", "#f4f4f5"],
  "Lab green":  ["#7cfc4d", "#050505", "#f4f4f5"],
  "Emerald":    ["#34d399", "#070908", "#f4f4f5"],
  "Acid lime":  ["#d4ff3a", "#060604", "#f4f4f5"],
};

const TREATMENT_LABELS = {
  spotlight: "Spotlight",
  split: "Split",
  manifesto: "Manifesto",
};

function hexToRgb(hex) {
  const m = hex.replace("#", "");
  const v = parseInt(m.length === 3 ? m.split("").map(c => c + c).join("") : m, 16);
  return [(v >> 16) & 255, (v >> 8) & 255, v & 255];
}
function rgba(hex, a) {
  const [r, g, b] = hexToRgb(hex);
  return `rgba(${r}, ${g}, ${b}, ${a})`;
}
function hexToHue(hex) {
  const [r, g, b] = hexToRgb(hex).map(v => v / 255);
  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  if (max === min) return 0;
  const d = max - min;
  let h;
  switch (max) {
    case r: h = ((g - b) / d + (g < b ? 6 : 0)); break;
    case g: h = ((b - r) / d + 2); break;
    default: h = ((r - g) / d + 4);
  }
  return (h / 6) * 360;
}
// Brand teal sampled from the source logo PNG.
const SOURCE_LOGO_HUE = 175;

function applyPalette(palette) {
  const [accent, bg] = palette;
  const root = document.documentElement;
  root.style.setProperty("--accent", accent);
  root.style.setProperty("--accent-glow", rgba(accent, 0.45));
  root.style.setProperty("--accent-soft", rgba(accent, 0.12));
  // Pick ink color (text on accent) based on lightness
  const [r, g, b] = hexToRgb(accent);
  const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
  root.style.setProperty("--accent-ink", lum > 0.6 ? "#042320" : "#042320");
  root.style.setProperty("--bg", bg);

  // Shift the logo to match the palette: rotate from brand teal hue (~175°) to
  // the accent hue. White text and black background are unaffected by hue-rotate.
  let delta = hexToHue(accent) - SOURCE_LOGO_HUE;
  if (delta > 180) delta -= 360;
  if (delta < -180) delta += 360;
  root.style.setProperty("--logo-hue-rotate", `${delta.toFixed(1)}deg`);
}

function applyMotion(motion) {
  const v = motion === "off" ? 0 : motion === "subtle" ? 0.5 : 1;
  document.documentElement.style.setProperty("--motion", v);
  document.documentElement.setAttribute("data-motion", motion);
}

function applyDensity(d) {
  const root = document.documentElement;
  if (d === "compact") {
    root.style.setProperty("--pad", "24px");
  } else if (d === "comfy") {
    root.style.setProperty("--pad", "40px");
  } else {
    root.style.setProperty("--pad", "32px");
  }
}

function applyFont(font) {
  document.documentElement.style.setProperty("--font-display", `"${font}", "Manrope", ui-sans-serif, system-ui, sans-serif`);
  if (font !== "Manrope") {
    document.documentElement.style.setProperty("--font-sans", `"${font}", "Manrope", ui-sans-serif, system-ui, sans-serif`);
  } else {
    document.documentElement.style.setProperty("--font-sans", `"Manrope", ui-sans-serif, system-ui, system-ui, sans-serif`);
  }
}

function useRoute() {
  const KNOWN = ["home", "markaloud", "work", "about", "contact"];
  const parse = () => {
    // Prefer real pathname routing when the URL has a real path
    const path = window.location.pathname.replace(/^\/|\/$/g, "").toLowerCase();
    if (path && KNOWN.includes(path)) return path;
    // Fallback: hash routing (works for file://, local previews, etc.)
    const h = window.location.hash || "";
    const p = h.replace(/^#\/?/, "").split("/")[0].toLowerCase();
    if (p && KNOWN.includes(p)) return p;
    return "home";
  };
  const [route, setRoute] = React.useState(parse);
  React.useEffect(() => {
    const onChange = () => {
      setRoute(parse());
      window.scrollTo({ top: 0, behavior: "instant" });
    };
    window.addEventListener("hashchange", onChange);
    window.addEventListener("popstate", onChange);
    return () => {
      window.removeEventListener("hashchange", onChange);
      window.removeEventListener("popstate", onChange);
    };
  }, []);
  const go = (r) => {
    // Use pushState for real URLs so each route has its own indexable URL
    const target = r === "home" ? "/" : "/" + r;
    try {
      // History API works on http/https; falls back to hash on file://
      if (window.location.protocol === "file:") {
        window.location.hash = r === "home" ? "" : "#/" + r;
      } else {
        if (window.location.pathname !== target) {
          window.history.pushState({}, "", target);
        }
        setRoute(r);
        window.scrollTo({ top: 0, behavior: "instant" });
      }
    } catch {
      window.location.hash = r === "home" ? "" : "#/" + r;
    }
  };
  return [route, go];
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [route, go] = useRoute();

  React.useEffect(() => { applyPalette(t.palette); }, [t.palette]);
  React.useEffect(() => { applyMotion(t.motion); }, [t.motion]);
  React.useEffect(() => { applyDensity(t.density); }, [t.density]);
  React.useEffect(() => { applyFont(t.displayFont); }, [t.displayFont]);

  // SEO: keep <title>, canonical, and Open Graph URL in sync with route.
  React.useEffect(() => {
    const meta = {
      home:      { title: "Otherworld — AI & Robotics Engineering · Adam Morgan",
                   desc: "Otherworld Dev Ltd — the AI & robotics engineering practice of Adam Morgan. Lecturer in Robotics, Swansea. Building Markaloud, an academic audio-marking tool." },
      markaloud: { title: "Markaloud — Academic audio-marking · Otherworld",
                   desc: "Markaloud — academic audio-marking for vivas and oral assessments. AI-structured, rubric-aligned, constructive feedback for educators." },
      work:      { title: "Selected work — Robotics, AI & embedded · Otherworld",
                   desc: "Selected engineering work — Bifrost (Thor robot GUI), RSIPI (KUKA control), ThorRR, drone tracking, high-speed drilling imaging, and Markaloud." },
      about:     { title: "About Adam Morgan — Lecturer in Robotics, AI engineer · Otherworld",
                   desc: "Adam Morgan — AI & robotics engineer. Lecturer in Robotics at Swansea. 5 peer-reviewed publications. Going full-time independent from July 2026." },
      contact:   { title: "Contact — Otherworld Dev Ltd",
                   desc: "Get in touch with Otherworld Dev Ltd — consulting and build engagements in AI, robotics, and software, available from July 2026." },
    }[route];
    if (!meta) return;
    document.title = meta.title;
    const setMeta = (sel, attr, value) => {
      const el = document.querySelector(sel);
      if (el) el.setAttribute(attr, value);
    };
    setMeta('meta[name="description"]', "content", meta.desc);
    setMeta('meta[property="og:title"]', "content", meta.title);
    setMeta('meta[property="og:description"]', "content", meta.desc);
    setMeta('meta[name="twitter:title"]', "content", meta.title);
    setMeta('meta[name="twitter:description"]', "content", meta.desc);
    const canon = "https://www.otherworld.dev" + (route === "home" ? "/" : "/" + route);
    setMeta('link[rel="canonical"]', "href", canon);
    setMeta('meta[property="og:url"]', "content", canon);
  }, [route]);

  React.useEffect(() => {
    // Update document body classes for grain
    document.body.classList.toggle("bg-grain", !!t.showGrain);
    document.body.classList.add("bg-ambient");
  }, [t.showGrain]);

  const screenLabel = ({
    home: "01 Home",
    markaloud: "02 Markaloud",
    work: "03 Work",
    about: "04 About",
    contact: "05 Contact",
  })[route];

  let Page;
  if (route === "markaloud") Page = <MarkaloudPage go={go} />;
  else if (route === "work") Page = <WorkPage go={go} />;
  else if (route === "about") Page = <AboutPage go={go} />;
  else if (route === "contact") Page = <ContactPage />;
  else Page = <HomePage go={go} treatment={t.markaloudTreatment} />;

  return (
    <div data-screen-label={screenLabel}>
      <Nav route={route} go={go} />
      <div key={route + ":" + t.markaloudTreatment}>
        {Page}
      </div>
      <Footer go={go} />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Color palette" />
        <TweakColor
          label="Palette"
          value={t.palette}
          options={Object.values(PALETTES)}
          onChange={(v) => setTweak("palette", v)}
        />

        <TweakSection label="Markaloud feature" />
        <TweakRadio
          label="Treatment"
          value={t.markaloudTreatment}
          options={["spotlight", "split", "manifesto"]}
          onChange={(v) => setTweak("markaloudTreatment", v)}
        />

        <TweakSection label="Motion" />
        <TweakRadio
          label="Intensity"
          value={t.motion}
          options={["off", "subtle", "lively"]}
          onChange={(v) => setTweak("motion", v)}
        />

        <TweakSection label="Layout" />
        <TweakRadio
          label="Density"
          value={t.density}
          options={["compact", "regular", "comfy"]}
          onChange={(v) => setTweak("density", v)}
        />
        <TweakSelect
          label="Display font"
          value={t.displayFont}
          options={["Manrope", "Space Grotesk", "Geist", "Inter Tight", "DM Sans"]}
          onChange={(v) => setTweak("displayFont", v)}
        />
        <TweakToggle
          label="Film grain"
          value={t.showGrain}
          onChange={(v) => setTweak("showGrain", v)}
        />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
document.body.classList.add("app-ready");
