/* global React, ReactDOM */
const { useState, useEffect, useRef, useMemo } = React;

// ---------------- Tweak defaults ----------------
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#5b8cff",
  "grain": 0.18,
  "density": "comfortable",
  "cursor": true,
  "italicWord": "Finance"
}/*EDITMODE-END*/;

const ACCENTS = [
  "#5b8cff", // electric blue
  "#7aa2ff", // soft sky
  "#3e63dd", // deep cobalt
  "#9bb5ff"  // ice
];

// ---------------- Helpers ----------------
function useLocalTime(tz = "Europe/London") {
  const [t, setT] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setT(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  const fmt = new Intl.DateTimeFormat("en-GB", {
    timeZone: tz,
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false
  });
  return fmt.format(t);
}

function useScrollProgress() {
  const [p, setP] = useState(0);
  useEffect(() => {
    const onScroll = () => {
      const h = document.documentElement;
      const max = h.scrollHeight - h.clientHeight;
      setP(max > 0 ? h.scrollTop / max : 0);
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return p;
}

function useInView(opts = { threshold: 0.18 }) {
  const ref = useRef(null);
  const [v, setV] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) setV(true);
    }, opts);
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return [ref, v];
}

// ---------------- Custom cursor ----------------
function Cursor({ enabled }) {
  const dotRef = useRef(null);
  const ringRef = useRef(null);
  const targetRef = useRef({ x: -100, y: -100 });
  const ringPosRef = useRef({ x: -100, y: -100 });
  const [hover, setHover] = useState(false);

  useEffect(() => {
    if (!enabled) return;
    const onMove = (e) => {
      targetRef.current = { x: e.clientX, y: e.clientY };
      if (dotRef.current) {
        dotRef.current.style.transform = `translate3d(${e.clientX}px, ${e.clientY}px, 0)`;
      }
      const el = document.elementFromPoint(e.clientX, e.clientY);
      const interactive =
        !!el &&
        (el.closest("a") ||
          el.closest("button") ||
          el.closest("[data-cursor='hover']"));
      setHover(!!interactive);
    };
    window.addEventListener("mousemove", onMove);
    let raf;
    const loop = () => {
      const r = ringPosRef.current;
      const t = targetRef.current;
      r.x += (t.x - r.x) * 0.18;
      r.y += (t.y - r.y) * 0.18;
      if (ringRef.current) {
        ringRef.current.style.transform = `translate3d(${r.x}px, ${r.y}px, 0)`;
      }
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => {
      window.removeEventListener("mousemove", onMove);
      cancelAnimationFrame(raf);
    };
  }, [enabled]);

  if (!enabled) return null;
  return (
    <React.Fragment>
      <div ref={dotRef} className={`cursor-dot ${hover ? "is-hover" : ""}`} />
      <div ref={ringRef} className={`cursor-ring ${hover ? "is-hover" : ""}`} />
    </React.Fragment>
  );
}

// ---------------- Reveal-on-scroll wrapper ----------------
function Reveal({ children, delay = 0, as: As = "div", className = "" }) {
  const [ref, v] = useInView();
  return (
    <As
      ref={ref}
      className={`reveal ${v ? "is-in" : ""} ${className}`}
      style={{ transitionDelay: `${delay}ms` }}
    >
      {children}
    </As>
  );
}

// ---------------- Magnetic link ----------------
function MagneticLink({ href, label, idx, total }) {
  const ref = useRef(null);
  const innerRef = useRef(null);
  useEffect(() => {
    const el = ref.current;
    const inner = innerRef.current;
    if (!el || !inner) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = e.clientX - (r.left + r.width / 2);
      const y = e.clientY - (r.top + r.height / 2);
      inner.style.transform = `translate(${x * 0.18}px, ${y * 0.28}px)`;
    };
    const onLeave = () => {
      inner.style.transform = "translate(0,0)";
    };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
    };
  }, []);
  return (
    <a
      ref={ref}
      href={href}
      target="_blank"
      rel="noopener noreferrer"
      className="link-row"
    >
      <span className="link-row__num">{String(idx + 1).padStart(2, "0")}</span>
      <span ref={innerRef} className="link-row__label">
        {label}
        <span className="link-row__arrow" aria-hidden="true">↗</span>
      </span>
      <span className="link-row__meta">/{total}</span>
    </a>
  );
}

// ---------------- App ----------------
function App() {
  const [tweaks, setTweak] = window.useTweaks
    ? window.useTweaks(TWEAK_DEFAULTS)
    : [TWEAK_DEFAULTS, () => {}];

  // expose accent as CSS var
  useEffect(() => {
    document.documentElement.style.setProperty("--accent", tweaks.accent);
    document.documentElement.style.setProperty("--grain-opacity", String(tweaks.grain));
    document.documentElement.dataset.density = tweaks.density;
  }, [tweaks.accent, tweaks.grain, tweaks.density]);

  const time = useLocalTime("Europe/London");
  const scrollP = useScrollProgress();

  // Parallax on hero based on scroll
  const heroOpacity = Math.max(0, 1 - scrollP * 2.6);
  const heroTranslate = scrollP * -60;

  const links = [
    { label: "LinkedIn", href: "https://www.linkedin.com/in/andnikolaou/" },
    { label: "GitHub", href: "https://github.com/andnik1998" }
  ];

  const tagline = tweaks.italicWord || "Finance";

  return (
    <React.Fragment>
      {/* scroll progress */}
      <div className="scroll-progress" style={{ transform: `scaleX(${scrollP})` }} />

      <Cursor enabled={tweaks.cursor} />

      <header className="top">
        <div className="mark" data-cursor="hover" aria-label="AN">
          <span>A</span>
          <span className="mark__slash">/</span>
          <span>N</span>
        </div>
        <div className="meta">
          <span className="meta__dot" />
          <span className="meta__label">London, UK</span>
          <span className="meta__sep">·</span>
          <span className="meta__time">{time}</span>
        </div>
      </header>

      {/* HERO */}
      <section
        className="hero"
        style={{ opacity: heroOpacity, transform: `translateY(${heroTranslate}px)` }}
        data-screen-label="01 Hero"
      >
        <h1 className="hero__name">
          <span className="word">Andreas</span>
          <span className="word">Nikolaou</span>
        </h1>

        <p className="hero__tagline">
          Computer&nbsp;Scientist working in{" "}
          <em className="ital">{tagline}</em>.
        </p>

        <div className="hero__scrollhint">
          <span className="line" />
          <span className="mono">scroll</span>
        </div>
      </section>

      {/* LINKS */}
      <section className="links" data-screen-label="02 Elsewhere">
        <Reveal as="div" className="links__head">
          <span className="mono">§ 02 · elsewhere</span>
        </Reveal>
        <div className="links__list">
          {links.map((l, i) => (
            <MagneticLink
              key={l.label}
              href={l.href}
              label={l.label}
              idx={i}
              total={links.length}
            />
          ))}
        </div>
      </section>      {/* FOOTER */}
      <footer className="foot">
        <div className="foot__col">
          <span className="mono dim">andnikolaou.com</span>
        </div>
        <div className="foot__col foot__col--center">
          <span className="mono dim"></span>
        </div>
        <div className="foot__col foot__col--right">
          <span className="mono dim">© {new Date().getFullYear()} Andreas Nikolaou</span>
        </div>
      </footer>

      {/* Tweaks Panel */}
      {window.TweaksPanel && (
        <window.TweaksPanel title="Tweaks">
          <window.TweakSection label="Accent">
            <window.TweakColor
              label="Hue"
              value={tweaks.accent}
              onChange={(v) => setTweak("accent", v)}
              options={ACCENTS}
            />
          </window.TweakSection>
          <window.TweakSection label="Texture">
            <window.TweakSlider
              label="Grain"
              value={Number(tweaks.grain).toFixed(2)}
              onChange={(v) => setTweak("grain", Number(v))}
              min={0}
              max={0.45}
              step={0.01}
            />
          </window.TweakSection>
          <window.TweakSection label="Layout">
            <window.TweakRadio
              label="Density"
              value={tweaks.density}
              onChange={(v) => setTweak("density", v)}
              options={["compact", "comfortable", "spacious"]}
            />
          </window.TweakSection>
          <window.TweakSection label="Cursor">
            <window.TweakToggle
              label="Custom cursor"
              value={tweaks.cursor}
              onChange={(v) => setTweak("cursor", v)}
            />
          </window.TweakSection>
          <window.TweakSection label="Copy">
            <window.TweakText
              label="Italic word"
              value={tweaks.italicWord}
              onChange={(v) => setTweak("italicWord", v)}
            />
          </window.TweakSection>
        </window.TweaksPanel>
      )}
    </React.Fragment>
  );
}

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