"use client";

import { useState, useRef } from "react";
import { motion } from "framer-motion";
import { Activity, Download, Upload, Server, RefreshCw } from "lucide-react";
import { CyberButton } from "../ui/cyber-button";
import { cn } from "@/lib/utils";

type TestStatus =
  | "idle"
  | "pinging"
  | "downloading"
  | "uploading"
  | "done"
  | "error";

export function SpeedtestClient() {
  const [status, setStatus] = useState<TestStatus>("idle");
  const [metrics, setMetrics] = useState({
    ping: 0,
    download: 0.0,
    upload: 0.0,
  });

  // Ref для принудительной отмены зависших тестов
  const abortControllerRef = useRef<AbortController | null>(null);

  const getProxyUrl = () => {
    return process.env.NODE_ENV === "production"
      ? "/api/proxy"
      : "http://localhost:3001";
  };

  const runTest = async () => {
    const baseUrl = getProxyUrl();
    setStatus("pinging");
    setMetrics({ ping: 0, download: 0, upload: 0 });

    const controller = new AbortController();
    abortControllerRef.current = controller;
    const signal = controller.signal;

    try {
      // 1. Замер PING (RTT)
      let totalPing = 0;
      let pingSuccessCount = 0;
      for (let i = 0; i < 5; i++) {
        const start = performance.now();
        try {
          await fetch(`${baseUrl}/api/speedtest/ping?nc=${Date.now()}`, {
            cache: "no-store",
            signal,
          });
          totalPing += performance.now() - start;
          pingSuccessCount++;
        } catch (e: any) {
          if (e?.name === "AbortError") throw e;
          // Игнорируем единичные дропы пакетов VPN при пинге
        }
      }
      if (pingSuccessCount === 0) throw new Error("Ping failed completely");
      setMetrics((m) => ({
        ...m,
        ping: Math.round(totalPing / pingSuccessCount),
      }));

      // 2. Замер DOWNLOAD
      setStatus("downloading");
      const dlStart = performance.now();
      const dlRes = await fetch(
        `${baseUrl}/api/speedtest/download?nocache=${Date.now()}`,
        { cache: "no-store", mode: "cors", signal },
      );

      const reader = dlRes.body?.getReader();
      let receivedBytes = 0;
      const MAX_DL_TIME_MS = 10000; // Ограничиваем скачивание 10 секундами для медленных VPN

      if (reader) {
        while (true) {
          const { done, value } = await reader.read();
          if (value) receivedBytes += value.length;

          const timeElapsed = performance.now() - dlStart;
          if (done || timeElapsed > MAX_DL_TIME_MS) {
            if (!done) await reader.cancel(); // Прерываем поток, если вышли за лимит времени
            break;
          }
        }
      }

      const dlTime = (performance.now() - dlStart) / 1000;
      const dlMbps = (receivedBytes * 8) / (1024 * 1024) / dlTime;
      setMetrics((m) => ({ ...m, download: Number(dlMbps.toFixed(2)) }));

      // 3. Замер UPLOAD
      setStatus("uploading");
      const UPLOAD_SIZE = 10 * 1024 * 1024; // 10 MB
      const uploadPayload = new Uint8Array(UPLOAD_SIZE);
      const chunk = new Uint8Array(65536); // Максимум для window.crypto

      // Полностью забиваем массив рандомом, иначе VPN его сожмет в ноль
      crypto.getRandomValues(chunk);
      for (let i = 0; i < UPLOAD_SIZE; i += chunk.length) {
        uploadPayload.set(
          chunk.subarray(0, Math.min(chunk.length, UPLOAD_SIZE - i)),
          i,
        );
      }

      const ulStart = performance.now();

      // Страховка от вечного зависания аплоада при обрыве туннеля
      const uploadTimeoutId = setTimeout(() => controller.abort(), 15000);

      await fetch(`${baseUrl}/api/speedtest/upload?nocache=${Date.now()}`, {
        method: "POST",
        body: uploadPayload,
        signal,
        headers: {
          "Content-Type": "application/octet-stream",
        },
      });

      clearTimeout(uploadTimeoutId);

      const ulTime = (performance.now() - ulStart) / 1000;
      const ulMbps = (UPLOAD_SIZE * 8) / (1024 * 1024) / ulTime;
      setMetrics((m) => ({ ...m, upload: Number(ulMbps.toFixed(2)) }));

      setStatus("done");
    } catch (err: any) {
      if (err.name === "AbortError") {
        console.warn("Speedtest aborted by timeout.");
      } else {
        console.error("Speedtest error:", err);
      }
      setStatus("error");
    } finally {
      abortControllerRef.current = null;
    }
  };

  const isRunning =
    status !== "idle" && status !== "done" && status !== "error";

  return (
    <div className="w-full max-w-3xl mx-auto bg-card/40 backdrop-blur-xl border border-border/50 rounded-[2rem] p-8 shadow-2xl relative overflow-hidden font-mono">
      {/* Декоративный фон */}
      <div className="absolute top-0 right-0 w-64 h-64 bg-primary/10 blur-[80px] rounded-full pointer-events-none -z-10" />

      <div className="flex flex-col md:flex-row items-center justify-between gap-8 mb-8 border-b border-border/50 pb-8">
        <div>
          <h2 className="text-2xl font-black uppercase text-foreground flex items-center gap-3">
            <Server className="text-primary size-6" />
            Uplink Diagnostics
          </h2>
          <p className="text-muted-foreground text-sm mt-2">
            Direct measurement through Netrunner MUX tunnel.
          </p>
        </div>

        <CyberButton onClick={runTest} disabled={isRunning} variant="primary">
          {!isRunning ? (
            <span className="flex items-center gap-2">
              <Activity className="size-4" />{" "}
              {status === "error" ? "RETRY TEST" : "INITIATE TEST"}
            </span>
          ) : (
            <span className="flex items-center gap-2 animate-pulse">
              <RefreshCw className="size-4 animate-spin" />{" "}
              {status.toUpperCase()}...
            </span>
          )}
        </CyberButton>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {/* PING */}
        <div
          className={cn(
            "p-6 rounded-2xl border transition-colors",
            status === "pinging"
              ? "bg-primary/10 border-primary/50"
              : "bg-muted/20 border-border/50",
          )}
        >
          <div className="text-muted-foreground text-xs uppercase tracking-widest mb-2 flex items-center gap-2">
            <Activity className="size-4 text-secondary" /> Latency
          </div>
          <div className="text-4xl font-black text-foreground">
            {metrics.ping}{" "}
            <span className="text-sm text-muted-foreground">ms</span>
          </div>
        </div>

        {/* DOWNLOAD */}
        <div
          className={cn(
            "p-6 rounded-2xl border transition-colors",
            status === "downloading"
              ? "bg-primary/10 border-primary/50"
              : "bg-muted/20 border-border/50",
          )}
        >
          <div className="text-muted-foreground text-xs uppercase tracking-widest mb-2 flex items-center gap-2">
            <Download className="size-4 text-green-500" /> Download
          </div>
          <div className="text-4xl font-black text-foreground">
            {metrics.download}{" "}
            <span className="text-sm text-muted-foreground">Mbps</span>
          </div>
        </div>

        {/* UPLOAD */}
        <div
          className={cn(
            "p-6 rounded-2xl border transition-colors",
            status === "uploading"
              ? "bg-primary/10 border-primary/50"
              : "bg-muted/20 border-border/50",
          )}
        >
          <div className="text-muted-foreground text-xs uppercase tracking-widest mb-2 flex items-center gap-2">
            <Upload className="size-4 text-primary" /> Upload
          </div>
          <div className="text-4xl font-black text-foreground">
            {metrics.upload}{" "}
            <span className="text-sm text-muted-foreground">Mbps</span>
          </div>
        </div>
      </div>
    </div>
  );
}
