"use client";

import { useEffect, useRef, useState, useCallback } from "react";
import { io, Socket } from "socket.io-client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Terminal, Send, Trash2, AlertCircle } from "lucide-react";
import { toast } from "sonner";

interface LogLine {
  text: string;
  timestamp: number;
  type: "info" | "warn" | "error" | "raw";
}

function classifyLine(line: string): LogLine["type"] {
  if (/\[WARN\]|WARNING/i.test(line)) return "warn";
  if (/\[ERROR\]|SEVERE|Exception|Error/i.test(line)) return "error";
  return "info";
}

function LineColor({ type }: { type: LogLine["type"] }) {
  const colors = {
    info: "text-zinc-300",
    warn: "text-amber-400",
    error: "text-red-400",
    raw: "text-zinc-500",
  };
  return colors[type];
}

const MAX_LINES = 1000;

export default function ConsolePage() {
  const [lines, setLines] = useState<LogLine[]>([]);
  const [command, setCommand] = useState("");
  const [connected, setConnected] = useState(false);
  const [history, setHistory] = useState<string[]>([]);
  const [historyIndex, setHistoryIndex] = useState(-1);
  const socketRef = useRef<Socket | null>(null);
  const scrollRef = useRef<HTMLDivElement>(null);
  const autoScrollRef = useRef(true);

  useEffect(() => {
    const socket = io("/console", {
      transports: ["websocket"],
    });
    socketRef.current = socket;

    socket.on("connect", () => setConnected(true));
    socket.on("disconnect", () => setConnected(false));
    socket.on("connect_error", () => {
      toast.error("Failed to connect to server console");
    });

    socket.on("output", (data: { line: string; timestamp: number }) => {
      setLines((prev) => {
        const newLine: LogLine = {
          text: data.line,
          timestamp: data.timestamp,
          type: classifyLine(data.line),
        };
        const updated = [...prev, newLine];
        return updated.length > MAX_LINES ? updated.slice(-MAX_LINES) : updated;
      });
    });

    // Receive buffered history on connect
    socket.on("history", (data: { lines: string[] }) => {
      const historicalLines = data.lines.map((line) => ({
        text: line,
        timestamp: Date.now(),
        type: classifyLine(line) as LogLine["type"],
      }));
      setLines(historicalLines);
    });

    return () => {
      socket.disconnect();
    };
  }, []);

  // Auto-scroll to bottom
  useEffect(() => {
    if (autoScrollRef.current && scrollRef.current) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }
  }, [lines]);

  const sendCommand = useCallback(() => {
    const cmd = command.trim();
    if (!cmd || !socketRef.current) return;

    // Add to local history
    setHistory((prev) => {
      const updated = [cmd, ...prev.filter((h) => h !== cmd)].slice(0, 50);
      return updated;
    });
    setHistoryIndex(-1);

    // Echo to console
    setLines((prev) => [
      ...prev,
      { text: `> ${cmd}`, timestamp: Date.now(), type: "raw" },
    ]);

    socketRef.current.emit("command", { command: cmd });
    setCommand("");
  }, [command]);

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter") {
      sendCommand();
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      const newIndex = Math.min(historyIndex + 1, history.length - 1);
      setHistoryIndex(newIndex);
      if (history[newIndex]) setCommand(history[newIndex]);
    } else if (e.key === "ArrowDown") {
      e.preventDefault();
      const newIndex = Math.max(historyIndex - 1, -1);
      setHistoryIndex(newIndex);
      setCommand(newIndex === -1 ? "" : history[newIndex] ?? "");
    }
  };

  const formatTime = (ts: number) =>
    new Date(ts).toLocaleTimeString("en", { hour12: false });

  return (
    <div className="p-6 h-full flex flex-col gap-4">
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold text-white">Server Console</h1>
          <p className="text-zinc-400 text-sm mt-1">
            Real-time server output and command input
          </p>
        </div>
        <div className="flex items-center gap-3">
          <Badge
            className={
              connected
                ? "bg-emerald-500/20 text-emerald-400 border-emerald-500/30"
                : "bg-red-500/20 text-red-400 border-red-500/30"
            }
          >
            <span
              className={`w-1.5 h-1.5 rounded-full mr-1.5 ${
                connected ? "bg-emerald-500" : "bg-red-500"
              } animate-pulse`}
            />
            {connected ? "Connected" : "Disconnected"}
          </Badge>
          <Button
            variant="outline"
            size="sm"
            className="border-zinc-700 text-zinc-400 hover:text-white"
            onClick={() => setLines([])}
          >
            <Trash2 className="w-4 h-4 mr-1.5" />
            Clear
          </Button>
        </div>
      </div>

      <Card className="bg-zinc-900 border-zinc-800 flex-1 min-h-0 flex flex-col">
        <CardHeader className="py-3 px-4 border-b border-zinc-800 flex-row items-center gap-2">
          <Terminal className="w-4 h-4 text-emerald-500" />
          <CardTitle className="text-sm font-medium text-zinc-400">
            Console Output
          </CardTitle>
          <span className="ml-auto text-xs text-zinc-600">
            {lines.length} lines
          </span>
        </CardHeader>

        <CardContent className="p-0 flex-1 min-h-0">
          <div
            ref={scrollRef}
            onScroll={(e) => {
              const el = e.currentTarget;
              autoScrollRef.current =
                el.scrollTop + el.clientHeight >= el.scrollHeight - 20;
            }}
            className="h-full overflow-y-auto font-mono text-xs p-4 space-y-0.5"
            style={{ maxHeight: "calc(100vh - 280px)" }}
          >
            {lines.length === 0 ? (
              <div className="flex flex-col items-center justify-center h-40 text-zinc-600">
                <Terminal className="w-8 h-8 mb-2 opacity-50" />
                <p>Waiting for server output...</p>
              </div>
            ) : (
              lines.map((line, i) => (
                <div key={i} className="flex gap-3 leading-5">
                  <span className="text-zinc-700 shrink-0 select-none">
                    {formatTime(line.timestamp)}
                  </span>
                  <span
                    className={`break-all ${
                      {
                        info: "text-zinc-300",
                        warn: "text-amber-400",
                        error: "text-red-400",
                        raw: "text-emerald-400",
                      }[line.type]
                    }`}
                  >
                    {line.text}
                  </span>
                </div>
              ))
            )}
          </div>
        </CardContent>

        {/* Command input */}
        <div className="p-3 border-t border-zinc-800 flex gap-2">
          <div className="flex-1 flex items-center gap-2 bg-zinc-950 border border-zinc-700 rounded-md px-3 focus-within:border-emerald-500/50 transition-colors">
            <span className="text-emerald-500 font-mono text-sm select-none">
              /
            </span>
            <input
              type="text"
              value={command}
              onChange={(e) => setCommand(e.target.value)}
              onKeyDown={handleKeyDown}
              placeholder="Enter server command... (↑↓ for history)"
              disabled={!connected}
              className="flex-1 bg-transparent py-2 text-sm text-white placeholder:text-zinc-600 outline-none font-mono"
            />
          </div>
          <Button
            onClick={sendCommand}
            disabled={!connected || !command.trim()}
            className="bg-emerald-600 hover:bg-emerald-500 text-white shrink-0"
          >
            <Send className="w-4 h-4" />
          </Button>
        </div>
      </Card>

      {!connected && (
        <div className="flex items-center gap-2 p-3 rounded-lg bg-amber-500/10 border border-amber-500/30 text-amber-400 text-sm">
          <AlertCircle className="w-4 h-4 shrink-0" />
          Console disconnected. The server may be offline or restarting.
        </div>
      )}
    </div>
  );
}
