"use client";

import { useEffect, useState, useRef } from "react";

type LineType = "input" | "success" | "info" | "dim";

interface ScriptLine {
  type: LineType;
  text: string;
  /** ms to wait before this line appears after the previous one finished */
  pauseBefore?: number;
  /** For input lines: typing speed override (ms/char) */
  charSpeed?: number;
}

const SCRIPT: ScriptLine[] = [
  { type: "input", text: "llmhosts serve", pauseBefore: 0 },
  { type: "info", text: "Starting proxy server...", pauseBefore: 200 },
  {
    type: "success",
    text: "✓ Local AI: 2 models detected (llama3.2, mistral)",
    pauseBefore: 500,
  },
  { type: "success", text: "✓ Routing: 3-tier intelligent", pauseBefore: 300 },
  {
    type: "success",
    text: "✓ Ready at http://localhost:4000",
    pauseBefore: 300,
  },
  { type: "input", text: "llmhosts tunnel", pauseBefore: 1200 },
  { type: "info", text: "Connecting WireGuard mesh...", pauseBefore: 300 },
  {
    type: "success",
    text: "✓ Tunnel: your-gpu.llmhosts.net",
    pauseBefore: 700,
  },
  {
    type: "dim",
    text: "  Your GPU. From anywhere.",
    pauseBefore: 200,
  },
];

const DEFAULT_CHAR_SPEED = 38; // ms per character for input lines
const OUTPUT_DURATION = 80; // ms for output lines to appear (brief flash-in)
const LOOP_PAUSE = 2800; // ms to pause at the end before restarting
const START_DELAY = 500; // ms before first line begins

function colorClass(type: LineType): string {
  switch (type) {
    case "input":
      return "text-gray-200";
    case "success":
      return "text-emerald-400";
    case "info":
      return "text-violet-300";
    case "dim":
      return "text-gray-500";
  }
}

interface VisibleLine {
  type: LineType;
  text: string;
}

export function AnimatedTerminal() {
  const [visibleLines, setVisibleLines] = useState<VisibleLine[]>([]);
  // typingLine: the line currently being typed (partial or full text shown)
  const [typingLine, setTypingLine] = useState<{
    type: LineType;
    text: string;
  } | null>(null);
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const prefersReducedMotion =
    typeof window !== "undefined"
      ? window.matchMedia("(prefers-reduced-motion: reduce)").matches
      : false;

  const clear = () => {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
  };

  useEffect(() => {
    if (prefersReducedMotion) {
      // Show all lines immediately
      setVisibleLines(SCRIPT.map(({ type, text }) => ({ type, text })));
      setTypingLine(null);
      return;
    }

    let cancelled = false;

    function schedule(ms: number, fn: () => void) {
      timeoutRef.current = setTimeout(() => {
        if (!cancelled) fn();
      }, ms);
    }

    function runSequence() {
      setVisibleLines([]);
      setTypingLine(null);

      let delay = START_DELAY;

      SCRIPT.forEach((line, index) => {
        delay += line.pauseBefore ?? 0;

        if (line.type === "input") {
          // Type characters one by one
          const speed = line.charSpeed ?? DEFAULT_CHAR_SPEED;
          const chars = line.text.split("");

          chars.forEach((_, charIndex) => {
            const partial = line.text.slice(0, charIndex + 1);
            const charDelay = delay + charIndex * speed;
            schedule(charDelay, () => {
              setTypingLine({ type: line.type, text: partial });
            });
          });

          // After all chars typed, move this line to visibleLines
          const doneAt = delay + chars.length * speed + 80;
          schedule(doneAt, () => {
            setTypingLine(null);
            setVisibleLines((prev) => [
              ...prev,
              { type: line.type, text: line.text },
            ]);
          });

          delay = doneAt;
        } else {
          // Output line: appears all at once
          schedule(delay, () => {
            setVisibleLines((prev) => [
              ...prev,
              { type: line.type, text: line.text },
            ]);
          });
          delay += OUTPUT_DURATION;
        }

        // After the last line, schedule a restart
        if (index === SCRIPT.length - 1) {
          schedule(delay + LOOP_PAUSE, () => {
            runSequence();
          });
        }
      });
    }

    runSequence();

    return () => {
      cancelled = true;
      clear();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <div className="glass rounded-xl overflow-hidden border border-white/10">
      {/* Terminal chrome */}
      <div className="flex items-center gap-1.5 border-b border-white/[0.06] bg-white/[0.03] px-4 py-3">
        <div className="h-3 w-3 rounded-full bg-red-500/60" />
        <div className="h-3 w-3 rounded-full bg-yellow-500/60" />
        <div className="h-3 w-3 rounded-full bg-green-500/60" />
        <span className="ml-2 text-xs text-gray-500 font-mono">Terminal</span>
      </div>

      {/* Terminal body */}
      <div className="p-5 font-mono text-sm min-h-[180px]">
        {/* Already-rendered lines */}
        {visibleLines.map((line, i) => (
          <div
            key={i}
            data-testid="terminal-line"
            className={colorClass(line.type)}
          >
            {line.type === "input" ? (
              <>
                <span className="text-gray-500 select-none">$ </span>
                {line.text}
              </>
            ) : (
              line.text
            )}
          </div>
        ))}

        {/* Currently-typing line */}
        {typingLine && (
          <div className={colorClass(typingLine.type)}>
            <span className="text-gray-500 select-none">$ </span>
            {typingLine.text}
            <span className="animate-pulse text-violet-400">▋</span>
          </div>
        )}
      </div>
    </div>
  );
}
