"use client";

import { IconLoader2 } from "@tabler/icons-react";
import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";

import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { formatBytes } from "@/lib/scoring";

interface HarEntry {
  url: string;
  method: string;
  status: number;
  type: string;
  size: number;
  time: number;
  timings: {
    blocked: number;
    dns: number;
    connect: number;
    ssl: number;
    send: number;
    wait: number;
    receive: number;
  };
  startOffset: number;
}

// Maps each HAR timing segment to its background color and the i18n key used to
// look up its localized label under `Waterfall.timings.*`.
type TimingSegment = "blocked" | "dns" | "connect" | "ssl" | "send" | "wait" | "receive";
const TIMING_COLORS: Record<
  TimingSegment,
  { bg: string; labelKey: "blocked" | "dns" | "connect" | "ssl" | "send" | "ttfb" | "download" }
> = {
  blocked: { bg: "bg-[#8b8b8b]", labelKey: "blocked" },
  dns: { bg: "bg-[#48a9a6]", labelKey: "dns" },
  connect: { bg: "bg-[#ffa400]", labelKey: "connect" },
  ssl: { bg: "bg-[#9b59b6]", labelKey: "ssl" },
  send: { bg: "bg-[#27ae60]", labelKey: "send" },
  wait: { bg: "bg-[#0cce6b]", labelKey: "ttfb" },
  receive: { bg: "bg-[#7bd0ff]", labelKey: "download" },
};

function categorize(mime: string): string {
  if (mime.includes("html")) return "html";
  if (mime.includes("css")) return "css";
  if (mime.includes("javascript") || mime.includes("ecmascript")) return "js";
  if (mime.includes("image")) return "image";
  if (mime.includes("font")) return "font";
  if (mime.includes("json") || mime.includes("xml")) return "data";
  return "other";
}

const TYPE_COLORS: Record<string, string> = {
  html: "text-[#7bd0ff]",
  css: "text-[#9b59b6]",
  js: "text-[#ffa400]",
  image: "text-[#0cce6b]",
  font: "text-[#e74c3c]",
  data: "text-[#48a9a6]",
  other: "text-muted-foreground",
};

interface Props {
  siteId: string;
}

export function WaterfallChart({ siteId }: Props) {
  const t = useTranslations("Waterfall");
  const [entries, setEntries] = useState<HarEntry[] | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetch(`/api/sites/${siteId}/har`)
      .then((r) => {
        if (!r.ok) throw new Error("No HAR");
        return r.json();
      })
      .then((har) => {
        const pageStart = har.log?.pages?.[0]?.startedDateTime
          ? new Date(har.log.pages[0].startedDateTime).getTime()
          : 0;

        const parsed: HarEntry[] = (har.log?.entries || []).map((e: Record<string, unknown>) => {
          const req = e.request as Record<string, unknown>;
          const res = e.response as Record<string, unknown>;
          const content = res?.content as Record<string, unknown>;
          const timings = e.timings as Record<string, number>;

          const startMs = e.startedDateTime
            ? new Date(e.startedDateTime as string).getTime() - pageStart
            : 0;

          return {
            url: (req?.url as string) ?? "",
            method: (req?.method as string) ?? "GET",
            status: (res?.status as number) ?? 0,
            type: categorize((content?.mimeType as string) ?? ""),
            size: (res?.bodySize as number) ?? 0,
            time: (e.time as number) ?? 0,
            timings: {
              blocked: Math.max(0, timings?.blocked ?? 0),
              dns: Math.max(0, timings?.dns ?? 0),
              connect: Math.max(0, timings?.connect ?? 0),
              ssl: Math.max(0, timings?.ssl ?? 0),
              send: Math.max(0, timings?.send ?? 0),
              wait: Math.max(0, timings?.wait ?? 0),
              receive: Math.max(0, timings?.receive ?? 0),
            },
            startOffset: startMs,
          };
        });
        setEntries(parsed);
        setLoading(false);
      })
      .catch((err) => {
        setError(err.message);
        setLoading(false);
      });
  }, [siteId]);

  if (loading) {
    return (
      <div className="flex items-center justify-center py-12">
        <IconLoader2 className="size-6 animate-spin text-primary" />
      </div>
    );
  }

  if (error || !entries) {
    return (
      <div className="rounded-xl bg-surface-container p-12 text-center text-muted-foreground">
        {t("empty")}
      </div>
    );
  }

  const totalTime = Math.max(...entries.map((e) => e.startOffset + e.time), 1);

  return (
    <div className="space-y-4">
      {/* Legend */}
      <div className="flex flex-wrap gap-4 text-[10px] font-bold tracking-widest text-muted-foreground uppercase">
        {Object.entries(TIMING_COLORS).map(([key, { bg, labelKey }]) => (
          <div key={key} className="flex items-center gap-1.5">
            <div className={`size-2.5 rounded-sm ${bg}`} />
            {t(`timings.${labelKey}`)}
          </div>
        ))}
      </div>

      {/* Entries */}
      <div className="overflow-hidden rounded-xl border border-[#45464d]/10 bg-surface-container">
        <div className="overflow-x-auto">
          <TooltipProvider delayDuration={0}>
            <table className="w-full text-xs">
              <thead>
                <tr className="bg-surface-container-high/50 text-[10px] font-black tracking-widest text-muted-foreground uppercase">
                  <th className="w-[40%] px-4 py-3 text-left">{t("columns.resource")}</th>
                  <th className="w-[60px] px-4 py-3 text-right">{t("columns.status")}</th>
                  <th className="w-[70px] px-4 py-3 text-right">{t("columns.size")}</th>
                  <th className="w-[60px] px-4 py-3 text-right">{t("columns.time")}</th>
                  <th className="w-[40%] px-4 py-3">{t("columns.waterfall")}</th>
                </tr>
              </thead>
              <tbody className="divide-y divide-[#45464d]/10">
                {entries.map((entry, i) => {
                  const urlShort = (() => {
                    try {
                      const u = new URL(entry.url);
                      const path = u.pathname + u.search;
                      return path.length > 60 ? `...${path.slice(-57)}` : path;
                    } catch {
                      return entry.url.slice(-60);
                    }
                  })();

                  return (
                    <tr key={i} className="transition-colors hover:bg-surface-container-high/30">
                      <td className="px-4 py-2">
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <span
                              className={`block max-w-[300px] truncate font-medium ${TYPE_COLORS[entry.type] ?? "text-muted-foreground"}`}
                            >
                              {urlShort}
                            </span>
                          </TooltipTrigger>
                          <TooltipContent
                            side="bottom"
                            className="max-w-md border-[#45464d]/20 glass-panel"
                          >
                            <p className="text-xs break-all">{entry.url}</p>
                          </TooltipContent>
                        </Tooltip>
                      </td>
                      <td className="px-4 py-2 text-right">
                        <span
                          className={
                            entry.status >= 400 ? "text-perf-danger" : "text-muted-foreground"
                          }
                        >
                          {entry.status}
                        </span>
                      </td>
                      <td className="px-4 py-2 text-right text-muted-foreground">
                        {entry.size > 0 ? formatBytes(entry.size) : "—"}
                      </td>
                      <td className="px-4 py-2 text-right text-muted-foreground">
                        {Math.round(entry.time)}ms
                      </td>
                      <td className="px-4 py-2">
                        <WaterfallBar entry={entry} totalTime={totalTime} />
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </TooltipProvider>
        </div>
      </div>

      <p className="text-right text-[10px] text-muted-foreground">
        {t("summary", { count: entries.length, ms: Math.round(totalTime) })}
      </p>
    </div>
  );
}

function WaterfallBar({ entry, totalTime }: { entry: HarEntry; totalTime: number }) {
  const t = useTranslations("Waterfall");
  const startPct = (entry.startOffset / totalTime) * 100;
  const { blocked, dns, connect, ssl, send, wait, receive } = entry.timings;
  const segments: { key: TimingSegment; ms: number }[] = (
    [
      { key: "blocked", ms: blocked },
      { key: "dns", ms: dns },
      { key: "connect", ms: connect },
      { key: "ssl", ms: ssl },
      { key: "send", ms: send },
      { key: "wait", ms: wait },
      { key: "receive", ms: receive },
    ] as const
  ).filter((s) => s.ms > 0);

  return (
    <div className="relative h-3 w-full">
      <div className="absolute top-0 flex h-full" style={{ left: `${startPct}%` }}>
        {segments.map((seg) => {
          const widthPct = (seg.ms / totalTime) * 100;
          const meta = TIMING_COLORS[seg.key];
          return (
            <div
              key={seg.key}
              className={`h-full ${meta?.bg ?? "bg-muted"}`}
              style={{ width: `${Math.max(1, widthPct)}px`, minWidth: "1px" }}
              title={`${meta ? t(`timings.${meta.labelKey}`) : seg.key}: ${Math.round(seg.ms)}ms`}
            />
          );
        })}
      </div>
    </div>
  );
}
