const { useState, useEffect, useRef, useMemo, useCallback } = React;

/// Hooks for the animations and such ///

// 3 Main hooks //

// useNow func for live clock
function useNow(intervalMs = 1000) {
  const [now, setNow] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), intervalMs);
    return () => clearInterval(id);
  }, [intervalMs]);
  return now;
}

// useInView to detect when element in viewport
function useInView(opts = {rootMargin: "0px 0px -10% 0px", threshold: 0.05}) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current || seen) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) {setSeen(true); io.disconnect(); } });
    }, opts);
    io.observe(ref.current);
    return () => io.disconnect();
  }, [seen]);
  return [ref, seen];
}

// useTypewriter types a string out. Im using this for some fun "typing" easter eggs
function useTypewriter(text, { speed = 22, start = true, onDone } = {}) {
  const [out, setOut] = useState("");
  const doneRef = useRef(false);
  useEffect(() => {
    if (!start) return;
    setOut(""); doneRef.current = false;
    let i = 0;
    const id = setInterval(() => {
      i++;
      setOut(text.slice(0, i));
      if (i >= text.length) {
        clearInterval(id);
        if (!doneRef.current && onDone) { doneRef.current = true; onDone(); }
      }
    }, speed);
    return () => clearInterval(id);
  }, [text, speed, start]);
  return out;
}

// Smaller hooks //

function Cursor({ char = "▌", inline = true }) {
  return <span className="blink accent" style={{
    display: inline ? "inline-block" : "block",
    fontFamily: "var(--mono)",
    transform: "translateY(1px)",
  }}>{char}</span>;
}

// Prompt component shows the user@host and such
function Prompt({ user = "clicky", host = "keys", path = "~", symbol = "$", showTime = false }) {
  const now = useNow(showTime ? 1000 : 60000);
  const t = now.toTimeString().slice(0, 8);
  return (
    <span style={{ whiteSpace: "nowrap" }}>
      {showTime && <span className="dimmer">[{t}] </span>}
      <span style={{ color: "var(--accent)" }}>{user}</span>
      <span className="dim">@</span>
      <span style={{ color: "var(--warn)" }}>{host}</span>
      <span className="dim">:</span>
      <span style={{ color: "color-mix(in oklch, var(--accent) 70%, white 20%)" }}>{path}</span>
      <span className="dim"> {symbol} </span>
    </span>
  );
}

// Shelline component is the primary section that uses useInView and useTypewriter
function ShellLine({ cmd, prompt = true, promptProps = {}, children, autoplay = false, speed = 25 }) {
  const [ref, seen] = useInView();
  const active = seen || autoplay;
  const typed = useTypewriter(cmd || "", {speed, start: active});
  const done = typed === (cmd || "");

  return (
    <div ref={ref} style={{ marginBottom: 18 }}>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 0 }}>
        {prompt && <Prompt {...promptProps} />}
        <span>{typed}{!done && active && <Cursor />}</span>
      </div>
      {done && (
        <div className="reveal" style={{
          marginTop: 6, animation: "fadeIn .35s ease-out both",
        }}>
          {children}
        </div>
      )}
      <style>{`@keyframes fadeIn{from{opacity:0;transform:translateY(2px)}to{opacity:1;transform:none}}`}</style>
    </div>
  );
}

// TerminalWindow is to show a linux style terminal
function TerminalWindow({ title = "clicky@keys: ~", children, style, dense = false, glow = true }) {
  return (
    <div style={{
      border: "1px solid var(--line)",
      background: "color-mix(in oklch, var(--bg-2) 92%, transparent)",
      borderRadius: 4,
      overflow: "hidden",
      boxShadow: glow
        ? "0 30px 80px -20px rgba(0,0,0,.6), 0 0 0 1px color-mix(in oklch, var(--accent) 8%, transparent), 0 0 60px -20px color-mix(in oklch, var(--accent) 25%, transparent)"
        : "0 30px 80px -20px rgba(0,0,0,.6)",
      backdropFilter: "blur(6px)",
      ...style,
    }}>
      <div style={{
        display: "flex", alignItems: "center", gap: 10,
        padding: "8px 12px",
        borderBottom: "1px solid var(--line)",
        background: "linear-gradient(to bottom, color-mix(in oklch, var(--bg-3) 80%, transparent), transparent)",
        fontSize: 12,
      }}>
        <span className="accent" style={{ fontWeight: 700, letterSpacing: .5 }}>
          [<span className="dim">1</span>]
        </span>
        <span className="dim" style={{ flex: 1, letterSpacing: .2 }}>
          {title}
        </span>
        <span style={{ display: "inline-flex", gap: 14, color: "var(--text-dimmer)", fontSize: 13, lineHeight: 1 }}>
          <span title="minimize">_</span>
          <span title="maximize" style={{ display: "inline-block", width: 10, height: 10, border: "1px solid currentColor" }} />
          <span title="close" style={{ color: "var(--crit)" }}>✕</span>
        </span>
      </div>
      <div style={{ padding: dense ? "14px 18px" : "22px 26px" }}>{children}</div>
    </div>
  );
}

// ASCII art of 'clicky'
const CLICKY_ASCII = String.raw`
 ██████╗ ██╗     ██╗ ██████╗██╗  ██╗██╗   ██╗
██╔════╝██║     ██║██╔════╝██║ ██╔╝╚██╗ ██╔╝
██║     ██║     ██║██║     █████╔╝  ╚████╔╝ 
██║     ██║     ██║██║     ██╔═██╗   ╚██╔╝  
╚██████╗███████╗██║╚██████╗██║  ██╗   ██║   
 ╚═════╝╚══════╝╚═╝ ╚═════╝╚═╝  ╚═╝   ╚═╝   
`.trim();

// Banner to show the ascii art 
function AsciiBanner({ text = CLICKY_ASCII }) {
  return (
    <pre style={{
      margin: 0,
      lineHeight: 1.05,
      fontSize: "clamp(10px, 1.5vw, 14px)",
      color: "var(--accent)",
      textShadow: "0 0 22px color-mix(in oklch, var(--accent) 60%, transparent)",
      fontFamily: "var(--mono)",
      fontWeight: 700,
    }}>{text}</pre>
  );
}

// Colored 'key caps' for keyboard shortcuts
function Kbd({ children }) {
  return (
    <kbd style={{
      display: "inline-block",
      padding: "1px 7px",
      borderRadius: 4,
      border: "1px solid var(--line-2)",
      background: "var(--bg-3)",
      color: "var(--text)",
      fontFamily: "var(--mono)",
      fontSize: 11,
      lineHeight: 1.5,
      boxShadow: "inset 0 -1px 0 var(--line)",
    }}>{children}</kbd>
  );
}

function Tag({ children, color }) {
  const c = color || "var(--accent)";
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 4,
      padding: "1px 7px",
      border: `1px solid color-mix(in oklch, ${c} 35%, transparent)`,
      background: `color-mix(in oklch, ${c} 8%, transparent)`,
      color: c,
      fontFamily: "var(--mono)",
      fontSize: 11,
      borderRadius: 999,
    }}>{children}</span>
  );
}

// LiveBar
function LiveBar({ label, min = 12, max = 60, color }) {
  const [v, setV] = useState(min + (max - min) * 0.5);
  useEffect(() => {
    const id = setInterval(() => {
      setV((prev) => {
        const delta = (Math.random() - 0.5) * 18;
        let n = prev + delta;
        if (n < min) n = min + (min - n) * 0.4;
        if (n > max) n = max - (n - max) * 0.4;
        return Math.max(min, Math.min(max, n));
      });
    }, 800);
    return () => clearInterval(id);
  }, [min, max]);
  const pct = Math.round(v);
  const c = color || "var(--accent)";
  return (
    <div style={{ display: "grid", gridTemplateColumns: "44px 1fr 32px", alignItems: "center", gap: 8, fontSize: 11 }}>
      <span className="dimmer">{label}</span>
      <span style={{
        position: "relative", height: 6, background: "var(--bg-3)",
        border: "1px solid var(--line)", borderRadius: 2, overflow: "hidden",
      }}>
        <span style={{
          position: "absolute", inset: 0, width: pct + "%",
          background: `linear-gradient(90deg, ${c}, color-mix(in oklch, ${c} 70%, white 30%))`,
          transition: "width .6s ease-out",
          boxShadow: `0 0 10px ${c}`,
        }} />
      </span>
      <span className="dim" style={{ textAlign: "right", fontVariantNumeric: "tabular-nums" }}>{pct}%</span>
    </div>
  );
}

function Clock() {
  const now = useNow(1000);
  const t = now.toTimeString().slice(0, 8);
  const d = now.toISOString().slice(0, 10);
  return (
    <div>
      <div style={{ fontSize: 26, letterSpacing: 1, fontWeight: 500 }} className="accent glow">{t}</div>
      <div className="dimmer" style={{ fontSize: 11 }}>{d} · UTC{-now.getTimezoneOffset()/60 >= 0 ? "+" : ""}{-now.getTimezoneOffset()/60}</div>
    </div>
  );
}

// EASTER EGG: ALL GAMERS KNOW THE KONAMI CODE
function CatTrail({ trigger }) {
  const [show, setShow] = useState(false);
  useEffect(() => {
    if (!trigger) return;
    setShow(true);
    const id = setTimeout(() => setShow(false), 5500);
    return () => clearTimeout(id);
  }, [trigger]);
  if (!show) return null;
  return (
    <>
      <style>{`
        @keyframes walk-cat{
          from{transform:translateX(-100px)}
          to{transform:translateX(110vw)}
        }
        @keyframes wag{0%,100%{transform:rotate(0)}50%{transform:rotate(8deg)}}
      `}</style>
      <div style={{
        position: "fixed", bottom: 20, left: 0, zIndex: 100,
        pointerEvents: "none", animation: "walk-cat 5.5s linear forwards",
        fontFamily: "var(--mono)", color: "var(--accent)", fontSize: 16,
        textShadow: "0 0 12px var(--accent)",
        whiteSpace: "pre",
      }}>
{` /\\_/\\  
( o.o ) 
 > ^ <  `}
      </div>
    </>
  );
}

// Command palette
function CommandPalette({ open, onClose, commands }) {
  const [q, setQ] = useState("");
  const [idx, setIdx] = useState(0);
  const inputRef = useRef(null);

  useEffect(() => { if (open) { setQ(""); setIdx(0); setTimeout(() => inputRef.current?.focus(), 30); } }, [open]);

  const matches = useMemo(() => {
    const s = q.trim().toLowerCase();
    if (!s) return commands;
    return commands.filter((c) => (c.title + " " + (c.hint || "") + " " + (c.keywords || "")).toLowerCase().includes(s));
  }, [q, commands]);

  useEffect(() => { if (idx >= matches.length) setIdx(0); }, [matches.length, idx]);

  const onKey = (e) => {
    if (e.key === "Escape") { onClose(); }
    else if (e.key === "ArrowDown") { setIdx((i) => Math.min(matches.length - 1, i + 1)); e.preventDefault(); }
    else if (e.key === "ArrowUp")   { setIdx((i) => Math.max(0, i - 1)); e.preventDefault(); }
    else if (e.key === "Enter")     { matches[idx]?.run(); onClose(); }
  };

  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, zIndex: 50,
      background: "color-mix(in oklch, var(--bg) 70%, transparent)",
      backdropFilter: "blur(4px)",
      display: "flex", justifyContent: "center", paddingTop: "16vh",
      animation: "fadeIn .12s ease-out",
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: "min(620px, 92vw)",
        background: "var(--bg-2)",
        border: "1px solid var(--line-2)",
        borderRadius: 10,
        boxShadow: "0 30px 80px -20px rgba(0,0,0,.6), 0 0 0 1px color-mix(in oklch, var(--accent) 14%, transparent)",
        overflow: "hidden",
        maxHeight: "65vh",
        display: "flex", flexDirection: "column",
      }}>
        <div style={{ display: "flex", alignItems: "center", padding: "12px 14px", borderBottom: "1px solid var(--line)" }}>
          <span style={{ color: "var(--accent)", marginRight: 8 }}>›</span>
          <input
            ref={inputRef}
            value={q}
            onChange={(e) => setQ(e.target.value)}
            onKeyDown={onKey}
            placeholder="type commands..."
            style={{
              flex: 1, background: "transparent", border: 0, outline: 0,
              color: "var(--text)", fontFamily: "var(--mono)", fontSize: 14,
            }}
          />
          <span className="dimmer" style={{ fontSize: 11 }}><Kbd>esc</Kbd></span>
        </div>
        <div style={{ overflowY: "auto", padding: 6 }}>
          {matches.length === 0 && (
            <div className="dim" style={{ padding: "20px 16px", fontStyle: "italic" }}>
              command not found. try: <span className="accent">help</span>
            </div>
          )}
          {matches.map((c, i) => (
            <div key={c.title} onMouseEnter={() => setIdx(i)} onClick={() => { c.run(); onClose(); }} style={{
              display: "flex", alignItems: "center", justifyContent: "space-between",
              padding: "9px 12px", borderRadius: 6, cursor: "default",
              background: i === idx ? "color-mix(in oklch, var(--accent) 12%, transparent)" : "transparent",
              border: "1px solid " + (i === idx ? "color-mix(in oklch, var(--accent) 25%, transparent)" : "transparent"),
            }}>
              <span style={{ display: "flex", gap: 10, alignItems: "center" }}>
                <span className="accent" style={{ width: 16 }}>{c.icon || "›"}</span>
                <span>{c.title}</span>
                {c.hint && <span className="dimmer" style={{ fontSize: 11, marginLeft: 8 }}>{c.hint}</span>}
              </span>
              {c.shortcut && <span className="dimmer" style={{ fontSize: 11 }}>{c.shortcut}</span>}
            </div>
          ))}
        </div>
        <div style={{ borderTop: "1px solid var(--line)", padding: "8px 12px", display: "flex", gap: 14, fontSize: 11 }} className="dimmer">
          <span><Kbd>↑↓</Kbd> navigate</span>
          <span><Kbd>↵</Kbd> run</span>
          <span><Kbd>esc</Kbd> close</span>
          <span style={{ marginLeft: "auto" }} className="dim">try <span className="accent">sudo</span></span>
        </div>
      </div>
    </div>
  );
}

// EASTER EGG: Toast for sudo and other easter eggs
function Toast({ children, onDone, kind = "info" }) {
  useEffect(() => {
    const id = setTimeout(onDone, 3200);
    return () => clearTimeout(id);
  }, []);
  const colors = {
    info: "var(--accent)",
    warn: "var(--warn)",
    crit: "var(--crit)",
  };
  const c = colors[kind] || colors.info;
  return (
    <div style={{
      position: "fixed", bottom: 24, left: "50%", transform: "translateX(-50%)",
      zIndex: 200,
      background: "var(--bg-2)",
      border: `1px solid ${c}`,
      color: "var(--text)",
      padding: "10px 16px",
      borderRadius: 6,
      fontFamily: "var(--mono)",
      fontSize: 13,
      boxShadow: `0 0 30px -5px ${c}, 0 20px 60px -10px rgba(0,0,0,.6)`,
      animation: "toastIn .22s ease-out",
    }}>
      <style>{`@keyframes toastIn{from{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%,0)}}`}</style>
      <span style={{ color: c, marginRight: 8 }}>●</span>
      {children}
    </div>
  );
}

Object.assign(window, {
  useNow, useInView, useTypewriter,
  Cursor, Prompt, ShellLine, TerminalWindow,
  AsciiBanner, CLICKY_ASCII,
  Kbd, Tag, LiveBar, Clock, CatTrail,
  CommandPalette, Toast,
});