"use client"

import { useEffect, useRef, useState } from "react"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog"
import { ScrollArea } from "./ui/scroll-area"
import { Activity, FileText, HardDrive, Clock, Info } from "lucide-react"
import { fetchApi } from "@/lib/api-config"
import { useI18n } from "../lib/i18n/provider"

interface ProcessDetail {
  pid: number
  comm: string
  cmdline: string
  exe: string | null
  cwd: string | null
  state: string
  ppid: number
  parent_name: string | null
  threads: number
  vm_rss_kb: number
  vm_size_kb: number
  vm_swap_kb: number
  user: string
  group: string
  uid: number
  gid: number
  start_time: string | null
  elapsed: string | null
  cpu: number
  mem: number
  io_read_bytes: number | null
  io_write_bytes: number | null
  fd_count: number | null
  captured_at: number
}

interface ProcessInfoModalProps {
  pid: number | null
  accent: { dot: string; bar: string; text: string }
  onClose: () => void
}

const REFRESH_MS = 3000

const formatKb = (kb: number | null | undefined): string => {
  if (kb == null) return "—"
  if (kb >= 1024 * 1024) return `${(kb / 1024 / 1024).toFixed(2)} GB`
  if (kb >= 1024) return `${(kb / 1024).toFixed(1)} MB`
  return `${kb} KB`
}

const formatBytes = (b: number | null | undefined): string => {
  if (b == null) return "—"
  if (b >= 1024 * 1024 * 1024) return `${(b / 1024 / 1024 / 1024).toFixed(2)} GB`
  if (b >= 1024 * 1024) return `${(b / 1024 / 1024).toFixed(1)} MB`
  if (b >= 1024) return `${(b / 1024).toFixed(1)} KB`
  return `${b} B`
}

// Linux process states from /proc/<pid>/status. The first char of `State:`
// is the canonical letter — the rest of the field is a human label like
// "(running)". We expand the bare letter to something readable.
const stateLabel = (state: string, t: (key: string) => string): string => {
  const rawLetter = (state || "").trim().charAt(0)
  const letter = rawLetter.toUpperCase()
  const map: Record<string, string> = {
    R: "running",
    S: "sleeping",
    D: "diskWait",
    Z: "zombie",
    T: rawLetter === "t" ? "tracingStop" : "stopped",
    X: "dead",
    I: "idle",
  }
  const key = map[letter]
  return key ? t(`details.processInfo.states.${key}`) : state || "—"
}

export function ProcessInfoModal({ pid, accent, onClose }: ProcessInfoModalProps) {
  const { language, t } = useI18n()
  const [data, setData] = useState<ProcessDetail | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(false)
  const [exited, setExited] = useState(false)
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
  const open = pid != null

  const stopPolling = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current)
      intervalRef.current = null
    }
  }

  const fetchDetail = async (silent = false) => {
    if (pid == null) return
    if (!silent) setLoading(true)
    setError(null)
    try {
      const res = await fetchApi<ProcessDetail>(`/api/processes/${pid}`)
      setData(res)
    } catch (e: any) {
      // 404 = the process exited while the modal was open. Expected for
      // short-lived helpers (pct exec, backup subprocesses, the `ps` snapshot
      // itself). Keep the last good snapshot on screen, stop polling, and
      // surface an info banner — NOT an error — so it doesn't look like a bug.
      if (e?.message?.includes("404")) {
        setExited(true)
        stopPolling()
      } else {
        setError(t("details.processInfo.fetchFailed"))
      }
    } finally {
      if (!silent) setLoading(false)
    }
  }

  useEffect(() => {
    if (pid == null) {
      setData(null)
      setError(null)
      setExited(false)
      stopPolling()
      return
    }
    setExited(false)
    fetchDetail()
    intervalRef.current = setInterval(() => fetchDetail(true), REFRESH_MS)
    return () => stopPolling()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pid])

  return (
    <Dialog open={open} onOpenChange={(v) => { if (!v) onClose() }}>
      <DialogContent className="max-w-2xl">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2 min-w-0">
            <span
              className="w-2 h-2 rounded-full flex-shrink-0"
              style={{ background: accent.dot }}
            />
            <span className="truncate font-mono text-base">{data?.comm || t("details.processInfo.titleFallback")}</span>
            <span className="text-xs text-muted-foreground font-mono flex-shrink-0">PID {pid}</span>
          </DialogTitle>
          <DialogDescription className="text-xs">
            {exited
              ? t("details.processInfo.descriptionExited", { pid: pid ?? "" })
              : t("details.processInfo.descriptionLive", { pid: pid ?? "", seconds: REFRESH_MS / 1000 })}
          </DialogDescription>
        </DialogHeader>

        {/* Info banner when the process has finished. Amber, not red — this is
            expected behavior for short-lived processes, not an error. */}
        {exited && (
          <div className="flex items-start gap-2 px-3 py-2 rounded-md border border-amber-500/30 bg-amber-500/10 text-xs text-amber-300">
            <Info className="h-4 w-4 flex-shrink-0 mt-0.5" />
            <div>
              <div className="font-medium text-amber-200">{t("details.processInfo.finishedTitle")}</div>
              <div className="text-amber-300/80 mt-0.5">
                {t("details.processInfo.finishedDescription")}
              </div>
            </div>
          </div>
        )}

        {error && !data ? (
          <div className="text-sm text-red-500 py-4">{error}</div>
        ) : !data ? (
          <div className="text-sm text-muted-foreground py-8 text-center">
            {loading ? t("details.processInfo.loading") : "—"}
          </div>
        ) : (
          <ScrollArea className={`max-h-[480px] pr-2 ${exited ? "opacity-75" : ""}`}>
            <div className="space-y-4">
              {/* Overview */}
              <Section icon={<Activity className="h-4 w-4 text-blue-400" />} title={t("details.processInfo.sections.overview")}>
                <Row label={t("details.processInfo.labels.state")} value={exited ? t("details.processInfo.states.exited") : stateLabel(data.state, t)} />
                <Row label={t("details.processInfo.labels.parent")} value={data.parent_name ? `${data.parent_name} (PID ${data.ppid})` : `PID ${data.ppid}`} mono />
                <Row label={t("details.processInfo.labels.threads")} value={String(data.threads)} mono />
                <Row label={t("details.processInfo.labels.openFds")} value={data.fd_count != null ? String(data.fd_count) : "—"} mono />
                <Row label={t("details.processInfo.labels.user")} value={`${data.user} (${data.uid})`} mono />
                <Row label={t("details.processInfo.labels.group")} value={`${data.group} (${data.gid})`} mono />
              </Section>

              {/* Resources */}
              <Section icon={<HardDrive className="h-4 w-4 text-amber-400" />} title={t("details.processInfo.sections.resources")}>
                <Row label={t("details.processInfo.labels.cpu")} value={`${data.cpu.toFixed(1)} %`} mono valueClass={accent.text} />
                <Row label={t("details.processInfo.labels.memory")} value={`${data.mem.toFixed(1)} %`} mono valueClass={accent.text} />
                <Row label={t("details.processInfo.labels.residentRss")} value={formatKb(data.vm_rss_kb)} mono />
                <Row label={t("details.processInfo.labels.virtualSize")} value={formatKb(data.vm_size_kb)} mono />
                <Row label={t("details.processInfo.labels.swap")} value={formatKb(data.vm_swap_kb)} mono />
                <Row label={t("details.processInfo.labels.ioRead")} value={formatBytes(data.io_read_bytes)} mono />
                <Row label={t("details.processInfo.labels.ioWrite")} value={formatBytes(data.io_write_bytes)} mono />
              </Section>

              {/* Command */}
              <Section icon={<FileText className="h-4 w-4 text-purple-400" />} title={t("details.processInfo.sections.command")}>
                <Row label={t("details.processInfo.labels.name")} value={data.comm} mono />
                <Row label={t("details.processInfo.labels.commandLine")} value={data.cmdline || data.comm} mono wrap />
                <Row label={t("details.processInfo.labels.executable")} value={data.exe || "—"} mono wrap />
                <Row label={t("details.processInfo.labels.workingDir")} value={data.cwd || "—"} mono wrap />
              </Section>

              {/* Times */}
              <Section icon={<Clock className="h-4 w-4 text-emerald-400" />} title={t("details.processInfo.sections.lifetime")}>
                <Row label={t("details.processInfo.labels.started")} value={data.start_time || "—"} mono />
                <Row label={t("details.processInfo.labels.runningFor")} value={data.elapsed || "—"} mono />
              </Section>
            </div>
          </ScrollArea>
        )}

        {data?.captured_at && (
          <div className="text-[10px] text-muted-foreground text-right mt-1">
            {exited ? t("details.processInfo.lastSeen") : t("details.processInfo.captured")}{" "}
            {new Date(data.captured_at * 1000).toLocaleTimeString(language)}
            {error ? ` · ${error}` : ""}
          </div>
        )}
      </DialogContent>
    </Dialog>
  )
}

function Section({ icon, title, children }: { icon: React.ReactNode; title: string; children: React.ReactNode }) {
  return (
    <div className="border border-border rounded-md overflow-hidden">
      <div className="flex items-center gap-2 px-3 py-2 bg-card text-xs font-medium uppercase tracking-wider text-muted-foreground border-b border-border">
        {icon}
        {title}
      </div>
      <div className="divide-y divide-border/40">{children}</div>
    </div>
  )
}

function Row({
  label,
  value,
  mono,
  wrap,
  valueClass,
}: {
  label: string
  value: string
  mono?: boolean
  wrap?: boolean
  valueClass?: string
}) {
  return (
    <div className="grid grid-cols-[110px_minmax(0,1fr)] gap-2 px-3 py-1.5 text-xs">
      <div className="text-muted-foreground">{label}</div>
      <div
        className={`${mono ? "font-mono" : ""} ${wrap ? "break-all" : "truncate"} ${valueClass || ""}`}
        title={value}
      >
        {value}
      </div>
    </div>
  )
}
