import { useEffect, useRef, useState, useCallback, useMemo, startTransition } from "react";
import { X, Pause, Play, Square, RotateCw, Hammer, Trash2, Terminal, Network, Globe, Info as InfoIcon, Activity, Variable, Settings, ChevronUp, ChevronDown, Eye, EyeOff, Copy, Check, Loader2, AlertTriangle, Maximize2, ExternalLink, Pencil, HelpCircle } from "lucide-react";
import type { Service, Stats, LogLine, WSMessage, Connection, DockerEvent } from "../../shared/types";

type Tab = "info" | "config" | "env" | "stats";

const SYSTEM_ENV_KEYS = new Set([
  "PATH", "HOME", "HOSTNAME", "TERM", "SHLVL", "PWD", "OLDPWD",
  "LANG", "LANGUAGE", "LC_ALL", "LC_CTYPE", "LC_MESSAGES", "LC_COLLATE",
  "DEBIAN_FRONTEND", "GPG_KEY", "GPG_KEYS",
  "PYTHON_VERSION", "PYTHON_PIP_VERSION", "PYTHON_SETUPTOOLS_VERSION",
  "PYTHON_GET_PIP_URL", "PYTHON_GET_PIP_SHA256", "PYTHON_SHA256",
  "NODE_VERSION", "YARN_VERSION", "NPM_CONFIG_LOGLEVEL",
  "JAVA_HOME", "JAVA_VERSION", "GOPATH", "GOVERSION",
  "PHPIZE_DEPS", "PHP_VERSION", "PHP_INI_DIR",
  "RUBY_VERSION", "GEM_HOME", "BUNDLE_PATH",
  "NGINX_VERSION", "NJS_VERSION",
  "REDIS_VERSION", "REDIS_DOWNLOAD_URL", "REDIS_DOWNLOAD_SHA",
  "PGDATA", "PG_MAJOR", "PG_VERSION", "PG_SHA256",
  "MYSQL_MAJOR", "MYSQL_VERSION", "MYSQL_SHELL_VERSION",
  "MONGO_VERSION", "MONGO_MAJOR", "MONGO_PACKAGE", "MONGO_REPO",
]);

const TABS: { id: Tab; label: string; icon: typeof InfoIcon }[] = [
  { id: "info", label: "Info", icon: InfoIcon },
  { id: "stats", label: "Stats", icon: Activity },
  { id: "env", label: "Env", icon: Variable },
  { id: "config", label: "Config", icon: Settings },
];

interface DetailPanelProps {
  service: Service;
  stats?: Stats;
  logLines: LogLine[];
  token: string;
  closing?: boolean;
  onClose: () => void;
  onAction: (serviceUid: string, expectedState: Service["state"], minDuration?: number) => void;
  clearProcessing: (uid: string) => void;
  sendMessage: (msg: WSMessage) => void;
  clearLogLines: () => void;
  connections: Connection[];
  services: Service[];
  getLogsSince: (uid: string) => number | undefined;
  initialLogsFullscreen?: boolean;
  envFiles: Record<string, string>;
  onEnvFileChange: (composeFile: string, envFile: string | null) => void;
  events: DockerEvent[];
}

export function DetailPanel({ service, stats, logLines, token, closing, onClose, onAction, clearProcessing, sendMessage, clearLogLines, connections, services, getLogsSince, initialLogsFullscreen, envFiles, onEnvFileChange, events }: DetailPanelProps) {
  const [initialLogs, setInitialLogs] = useState<LogLine[]>([]);
  const [autoScroll, setAutoScroll] = useState(true);
  const [loading, setLoading] = useState(true);
  const scrollRef = useRef<HTMLDivElement>(null);
  const subscribedRef = useRef<string | null>(null);
  const [visible, setVisible] = useState(false);
  const [activeTab, setActiveTab] = useState<Tab>("info");
  const [logsExpanded, setLogsExpanded] = useState(false);
  const [envVisibleAll, setEnvVisibleAll] = useState(false);
  const [envVisibleSet, setEnvVisibleSet] = useState<Set<number>>(new Set());
  const [copiedEnvIdx, setCopiedEnvIdx] = useState<number | null>(null);
  const [logsModal, setLogsModal] = useState(!!initialLogsFullscreen);
  const modalScrollRef = useRef<HTMLDivElement>(null);
  const [envFileEditing, setEnvFileEditing] = useState(false);
  const [envFileOptions, setEnvFileOptions] = useState<string[]>([]);
  const [envFileSelected, setEnvFileSelected] = useState<string>("");

  // Exec state
  const [execOpen, setExecOpen] = useState(false);
  const [execCmd, setExecCmd] = useState("");
  const [execLoading, setExecLoading] = useState(false);
  const [execResult, setExecResult] = useState<{ output: string; exitCode: number } | null>(null);
  const [execError, setExecError] = useState<string | null>(null);

  // Scroll modal to bottom when opened or when logs arrive
  useEffect(() => {
    if (logsModal && modalScrollRef.current) {
      modalScrollRef.current.scrollTop = modalScrollRef.current.scrollHeight;
    }
  }, [logsModal, initialLogs, logLines]);
  const isProcessing = (service.state as string) === "processing";
  const processingStartedAt = (service as any)._processingStartedAt as number | undefined;
  const [elapsed, setElapsed] = useState(0);
  const prevProcessingRef = useRef(false);
  const actionTimestampRef = useRef<number | null>(null);

  // Timer for processing counter
  useEffect(() => {
    if (!isProcessing || !processingStartedAt) { setElapsed(0); return; }
    setElapsed(Math.floor((Date.now() - processingStartedAt) / 1000));
    const interval = setInterval(() => {
      setElapsed(Math.floor((Date.now() - processingStartedAt) / 1000));
    }, 1000);
    return () => clearInterval(interval);
  }, [isProcessing, processingStartedAt]);
  const [actionLoading, setActionLoading] = useState<string | null>(null);
  const [actionResult, setActionResult] = useState<{ type: "success" | "error"; message: string } | null>(null);
  const [confirmAction, setConfirmAction] = useState<"stop" | "restart" | "rebuild" | "remove" | null>(null);

  const executeAction = useCallback(async (action: "stop" | "start" | "restart" | "rebuild" | "remove") => {
    setActionLoading(action);
    setActionResult(null);
    setConfirmAction(null);
    actionTimestampRef.current = Math.floor(Date.now() / 1000);

    // Optimistic processing — set BEFORE fetch
    const expectedState: Service["state"] =
      action === "stop" || action === "remove" ? "exited" :
      action === "start" || action === "restart" || action === "rebuild" ? "running" :
      service.state;
    const minDuration = action === "restart" ? 2000 : action === "rebuild" ? 3000 : 0;
    onAction(service.uid, expectedState, minDuration);
    setInitialLogs([]);
    clearLogLines();

    try {
      const headers: Record<string, string> = {};
      if (token) headers["Authorization"] = `Bearer ${token}`;
      const res = await fetch(`/api/containers/${service.id}/${action}`, { method: "POST", headers });
      const data = await res.json();
      if (res.ok) {
        setActionResult({ type: "success", message: `${action} successful` });
        if (action === "remove") {
          setTimeout(() => handleClose(), 1000);
        }
      } else {
        clearProcessing(service.uid);
        setActionResult({ type: "error", message: data.error || `Failed to ${action}` });
      }
    } catch {
      clearProcessing(service.uid);
      setActionResult({ type: "error", message: `Failed to ${action}` });
    } finally {
      setActionLoading(null);
      setTimeout(() => setActionResult(null), 3000);
    }
  }, [service.id, service.uid, token, onAction, clearProcessing]);

  const runExec = useCallback(async () => {
    if (!execCmd.trim()) return;
    setExecLoading(true);
    setExecResult(null);
    setExecError(null);
    try {
      const headers: Record<string, string> = { "Content-Type": "application/json" };
      if (token) headers["Authorization"] = `Bearer ${token}`;
      const res = await fetch(`/api/containers/${service.id}/exec`, {
        method: "POST",
        headers,
        body: JSON.stringify({ cmd: execCmd }),
      });
      const data = await res.json();
      if (res.ok && data.ok) {
        setExecResult({ output: data.output, exitCode: data.exitCode });
      } else {
        setExecError(data.error || "Exec failed");
      }
    } catch {
      setExecError("Network error");
    } finally {
      setExecLoading(false);
    }
  }, [execCmd, service.id, token]);

  // Re-subscribe logs when exiting processing state
  useEffect(() => {
    const wasProcessing = prevProcessingRef.current;
    prevProcessingRef.current = isProcessing;
    if (wasProcessing && !isProcessing) {
      // Service just finished processing — re-fetch logs (only new ones since the action)
      setInitialLogs([]);
      clearLogLines();
      const headers: Record<string, string> = {};
      if (token) headers["Authorization"] = `Bearer ${token}`;
      const since = actionTimestampRef.current;
      const sinceParam = since ? `&since=${since}` : "";
      fetch(`/api/logs/${service.id}?tail=200${sinceParam}`, { headers })
        .then((r) => r.ok ? r.json() : [])
        .then((lines: LogLine[]) => setInitialLogs(lines))
        .catch(() => {});
      sendMessage({ type: "subscribe_logs", container: service.id });
    }
  }, [isProcessing, service.state, service.id, token, sendMessage, clearLogLines]);

  // Slide-in animation
  useEffect(() => {
    requestAnimationFrame(() => setVisible(true));
  }, []);

  // React to external close (pane click)
  useEffect(() => {
    if (closing) setVisible(false);
  }, [closing]);

  // Slide-out + zoom-out in parallel
  const handleClose = useCallback(() => {
    setVisible(false);
    onClose();
  }, [onClose]);

  // Fetch initial logs + subscribe
  useEffect(() => {
    setInitialLogs([]);
    setLoading(true);
    clearLogLines();
    initialScrollDone.current = false;

    const headers: Record<string, string> = {};
    if (token) headers["Authorization"] = `Bearer ${token}`;

    const since = getLogsSince(service.uid);
    const sinceParam = since ? `&since=${since}` : "";
    fetch(`/api/logs/${service.id}?tail=200${sinceParam}`, { headers })
      .then((r) => r.ok ? r.json() : [])
      .then((lines: LogLine[]) => {
        setInitialLogs(lines);
        setLoading(false);
      })
      .catch(() => setLoading(false));

    sendMessage({ type: "subscribe_logs", container: service.id });
    subscribedRef.current = service.id;

    return () => {
      if (subscribedRef.current) {
        sendMessage({ type: "unsubscribe_logs" });
        subscribedRef.current = null;
      }
    };
  }, [service.id, token, sendMessage, clearLogLines]);

  // Auto-scroll
  const initialScrollDone = useRef(false);
  useEffect(() => {
    if (!autoScroll || !scrollRef.current) return;
    programmaticScroll.current = true;
    // Instant scroll until initial logs are loaded, then smooth
    if (!initialScrollDone.current && initialLogs.length > 0) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
      initialScrollDone.current = true;
    } else if (initialScrollDone.current) {
      scrollRef.current.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
    }
  }, [initialLogs, logLines, autoScroll]);

  const programmaticScroll = useRef(false);
  const manualPause = useRef(false);
  const handleScroll = useCallback(() => {
    if (!scrollRef.current) return;
    if (programmaticScroll.current) { programmaticScroll.current = false; return; }
    const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;
    const atBottom = scrollHeight - scrollTop - clientHeight < 5;
    if (manualPause.current) {
      // Only clear manual pause when user scrolls exactly to bottom
      if (atBottom) { manualPause.current = false; setAutoScroll(true); }
      return;
    }
    setAutoScroll((prev) => prev === atBottom ? prev : atBottom);
  }, []);

  // Docker events as special log lines
  const eventLogLines = useMemo(() => {
    return events
      .filter((e) => e.service === service.uid)
      .map((e): LogLine => ({
        container: service.id,
        line: `[DOCKER] Container ${e.action}`,
        timestamp: new Date(e.time * 1000).toISOString(),
        stream: "stderr",
      }));
  }, [events, service.uid, service.id]);

  const allLines = useMemo(() => {
    const combined = [...initialLogs, ...logLines, ...eventLogLines];
    combined.sort((a, b) => (a.timestamp || "").localeCompare(b.timestamp || ""));
    return combined;
  }, [initialLogs, logLines, eventLogLines]);

  const connectedSvcs = useMemo(() => {
    const connectedUids = new Set<string>();
    for (const c of connections) {
      if (c.from === service.uid) connectedUids.add(c.to);
      if (c.to === service.uid) connectedUids.add(c.from);
    }
    return services.filter((s) => connectedUids.has(s.uid));
  }, [connections, services, service.uid]);

  const isCrashed = (service.state as string) === "crashed";
  const stateColor = isProcessing ? "text-yellow-400" :
    isCrashed ? "text-orange-400" :
    service.state === "running" ? "text-emerald-400" :
    service.state === "exited" || service.state === "dead" ? "text-red-400" :
    "text-yellow-400";

  const stateDot = isProcessing ? "bg-yellow-400 animate-pulse" :
    isCrashed ? "bg-orange-400" :
    service.state === "running" ? "bg-emerald-400" :
    service.state === "exited" || service.state === "dead" ? "bg-red-400" :
    "bg-yellow-400";

  return (
    <div
      className={`absolute top-0 left-0 bottom-0 w-[900px] bg-slate-900/95 backdrop-blur-sm border-r border-slate-700/60 flex flex-col z-50 rounded-l-xl transition-transform duration-[400ms] ease-out ${visible ? "translate-x-0" : "-translate-x-full"}`}
    >
      {/* Header */}
      <div className="flex items-center justify-between px-4 py-3 border-b border-slate-800 shrink-0">
        <div className="flex items-center gap-2.5">
          <span className={`w-2 h-2 rounded-full ${stateDot}`} />
          <span className="text-sm font-semibold text-white truncate">{service.name}</span>
          {service.ports.length > 0 && service.state === "running" && (
            <a
              href={`http://${window.location.hostname}:${service.ports[0].host}`}
              target="_blank"
              rel="noopener noreferrer"
              className="flex items-center gap-1 text-slate-500 hover:text-cyan-400 transition-colors"
              title={`Open http://${window.location.hostname}:${service.ports[0].host}`}
            >
              <ExternalLink size={12} />
              <span className="text-[11px] font-mono">:{service.ports[0].host}</span>
            </a>
          )}
          <span className={`text-xs font-mono ${stateColor} flex items-center gap-1`}>
            {isProcessing ? `processing... ${elapsed}s` :
             isCrashed ? <><AlertTriangle size={11} />crashed (exit {service.exit_code}{service.oom_killed ? ", OOM" : ""})</> :
             service.state}
          </span>
        </div>
        <div className="flex items-center gap-1.5">
          {/* Action buttons */}
          {isProcessing ? (
            <div className="flex items-center gap-1.5 px-2 py-1 text-[11px] font-medium text-yellow-400">
              <Loader2 size={12} className="animate-spin" />
              Processing...
            </div>
          ) : (
            <>
              {service.compose_file && (
                <button
                  onClick={() => setConfirmAction("rebuild")}
                  disabled={!!actionLoading}
                  className="flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-cyan-400 hover:bg-cyan-400/10 transition-colors disabled:opacity-40"
                  title="Rebuild"
                >
                  {actionLoading === "rebuild" ? <Loader2 size={12} className="animate-spin" /> : <Hammer size={12} />}
                  Rebuild
                </button>
              )}
              {service.state === "running" ? (
                <>
                  <button
                    onClick={() => setConfirmAction("restart")}
                    disabled={!!actionLoading}
                    className="flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-yellow-400 hover:bg-yellow-400/10 transition-colors disabled:opacity-40"
                    title="Restart"
                  >
                    {actionLoading === "restart" ? <Loader2 size={12} className="animate-spin" /> : <RotateCw size={12} />}
                    Restart
                  </button>
                  <button
                    onClick={() => setConfirmAction("stop")}
                    disabled={!!actionLoading}
                    className="flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-red-400 hover:bg-red-400/10 transition-colors disabled:opacity-40"
                    title="Stop"
                  >
                    {actionLoading === "stop" ? <Loader2 size={12} className="animate-spin" /> : <Square size={12} />}
                    Stop
                  </button>
                </>
              ) : (
                <>
                  <button
                    onClick={() => setConfirmAction("remove")}
                    disabled={!!actionLoading}
                    className="flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-red-400 hover:bg-red-400/10 transition-colors disabled:opacity-40"
                    title="Remove"
                  >
                    {actionLoading === "remove" ? <Loader2 size={12} className="animate-spin" /> : <Trash2 size={12} />}
                    Remove
                  </button>
                  <button
                    onClick={() => executeAction("start")}
                    disabled={!!actionLoading}
                    className={`flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium transition-colors disabled:opacity-40 ${
                      isCrashed ? "text-orange-400 hover:bg-orange-400/10" : "text-emerald-400 hover:bg-emerald-400/10"
                    }`}
                    title={isCrashed ? "Retry start" : "Start"}
                  >
                    {actionLoading === "start" ? <Loader2 size={12} className="animate-spin" /> : <Play size={12} />}
                    {isCrashed ? "Retry" : "Start"}
                  </button>
                </>
              )}
            </>
          )}

          <div className="w-px h-4 bg-slate-700 mx-1" />
          <button
            onClick={handleClose}
            className="p-1.5 rounded hover:bg-slate-700/60 text-slate-400 hover:text-slate-200 transition-colors"
            title="Close"
          >
            <X size={14} />
          </button>
        </div>
      </div>

      {/* Confirmation dialog */}
      {confirmAction && (
        <div className="px-4 py-2.5 bg-slate-800/90 border-b border-slate-700/60 flex items-center gap-3 shrink-0">
          <AlertTriangle size={14} className={`shrink-0 ${
            confirmAction === "stop" || confirmAction === "remove" ? "text-red-400" :
            confirmAction === "rebuild" ? "text-cyan-400" :
            "text-yellow-400"
          }`} />
          <span className="text-xs text-slate-300 flex-1">
            {confirmAction === "stop" ? "Stop this container? This will interrupt the service." :
             confirmAction === "restart" ? "Restart this container? This will briefly interrupt the service." :
             confirmAction === "remove" ? "Remove this container? This will stop and delete it." :
             "Rebuild this container? This will rebuild the image and recreate the container."}
          </span>
          <button
            onClick={() => executeAction(confirmAction)}
            className={`px-3 py-1 rounded text-[11px] font-medium text-white transition-colors ${
              confirmAction === "stop" || confirmAction === "remove" ? "bg-red-700 hover:bg-red-600" :
              confirmAction === "rebuild" ? "bg-cyan-700 hover:bg-cyan-600" :
              "bg-yellow-700 hover:bg-yellow-600"
            }`}
          >
            {confirmAction === "stop" ? "Stop" : confirmAction === "restart" ? "Restart" : confirmAction === "remove" ? "Remove" : "Rebuild"}
          </button>
          <button
            onClick={() => setConfirmAction(null)}
            className="px-3 py-1 rounded text-[11px] font-medium text-slate-400 hover:text-slate-200 bg-slate-700 hover:bg-slate-600 transition-colors"
          >
            Cancel
          </button>
        </div>
      )}

      {/* Tabs */}
      <div className="flex items-center border-b border-slate-800 shrink-0">
        {TABS.map((tab) => {
          const Icon = tab.icon;
          const isActive = activeTab === tab.id;
          return (
            <button
              key={tab.id}
              onClick={() => { setActiveTab(tab.id); setLogsExpanded(false); }}
              className={`flex-1 flex items-center justify-center gap-1.5 py-2.5 text-xs font-medium relative transition-colors ${
                isActive ? "text-cyan-400" : "text-slate-500 hover:text-slate-300"
              }`}
            >
              <Icon size={12} />
              {tab.label}
              <span className={`absolute bottom-0 left-0 right-0 h-px bg-cyan-400 transition-transform duration-300 ease-out origin-center ${isActive ? "scale-x-100" : "scale-x-0"}`} />
            </button>
          );
        })}
      </div>

      {/* Tab content + Logs below */}
      <div className="flex-1 min-h-0 flex flex-col">
        {/* Tab content area */}
        <div style={{ flexBasis: logsExpanded ? "0px" : "75%", flexShrink: 0, transition: "flex-basis 300ms ease-in-out, padding 300ms ease-in-out" }} className={`overflow-hidden ${logsExpanded ? "" : "overflow-y-auto"}`}>
          {/* Info tab */}
          {activeTab === "info" && (
            <div className="px-4 py-3 space-y-3">
              {/* Crash banner */}
              {isCrashed && (
                <div className="flex items-start gap-2.5 bg-orange-500/10 border border-orange-500/30 rounded-lg px-3 py-2.5">
                  <AlertTriangle size={16} className="text-orange-400 shrink-0 mt-0.5" />
                  <div className="text-xs space-y-1">
                    <div className="font-semibold text-orange-300">Container crashed</div>
                    <div className="text-slate-400">
                      Exit code: <span className="text-orange-300 font-mono">{service.exit_code}</span>
                      {service.oom_killed && <span className="ml-2 text-red-400 font-semibold">OOM Killed</span>}
                      {service.restart_count > 0 && <span className="ml-2">Restarted <span className="text-orange-300 font-mono">{service.restart_count}</span> times</span>}
                    </div>
                    <div className="text-slate-500">Check the logs below for details</div>
                  </div>
                </div>
              )}
              {service.status && (
                <DetailRow label="Status" value={service.status} />
              )}
              <DetailRow label="Image" value={service.image} mono />
              <DetailRow label="Container" value={service.id.slice(0, 12)} mono />
              <DetailRow label="Project" value={service.project} />
              {service.compose_file && (
                <DetailRow label="Compose" value={service.compose_file} mono />
              )}

              {service.compose_file && (
                <div>
                  <span className="text-[11px] uppercase tracking-wider text-slate-500 mb-0.5 flex items-center gap-1">
                    Env File
                    <span className="relative group/tip">
                      <HelpCircle size={11} className="text-slate-600 hover:text-slate-400 cursor-help transition-colors" />
                      <span className="absolute left-full top-1/2 -translate-y-1/2 ml-1.5 px-2.5 py-1.5 bg-slate-700 text-slate-200 text-[11px] normal-case tracking-normal rounded-md shadow-lg whitespace-nowrap opacity-0 pointer-events-none group-hover/tip:opacity-100 transition-opacity z-10">
                        Only files starting with .env are detected
                      </span>
                    </span>
                  </span>
                  {envFileEditing ? (
                    <div className="flex items-center gap-1.5">
                      <select
                        value={envFileSelected}
                        onChange={(e) => setEnvFileSelected(e.target.value)}
                        className="flex-1 bg-slate-800 border border-slate-600 rounded px-2 py-1 text-sm font-mono text-slate-200 focus:outline-none focus:border-cyan-500"
                      >
                        <option value="">Auto (detect)</option>
                        {envFileOptions.map((f) => (
                          <option key={f} value={f}>{f}</option>
                        ))}
                      </select>
                      <button
                        onClick={() => {
                          onEnvFileChange(service.compose_file!, envFileSelected || null);
                          setEnvFileEditing(false);
                        }}
                        className="p-1 rounded text-emerald-400 hover:bg-emerald-400/10 transition-colors"
                        title="Save"
                      >
                        <Check size={14} />
                      </button>
                      <button
                        onClick={() => setEnvFileEditing(false)}
                        className="p-1 rounded text-slate-400 hover:bg-slate-700 transition-colors"
                        title="Cancel"
                      >
                        <X size={14} />
                      </button>
                    </div>
                  ) : (
                    <div className="flex items-center gap-1.5">
                      <span className={`text-sm break-all ${envFiles[service.compose_file!] ? "font-mono text-slate-200" : "text-slate-500 italic"}`}>
                        {envFiles[service.compose_file!] || "Auto"}
                      </span>
                      <button
                        onClick={() => {
                          setEnvFileSelected(envFiles[service.compose_file!] || "");
                          const headers: Record<string, string> = {};
                          if (token) headers["Authorization"] = `Bearer ${token}`;
                          fetch(`/api/env-files/detect/${service.id}`, { headers })
                            .then((r) => r.ok ? r.json() : { files: [] })
                            .then((data: { files: string[] }) => setEnvFileOptions(data.files))
                            .catch(() => setEnvFileOptions([]));
                          setEnvFileEditing(true);
                        }}
                        className="p-1 rounded text-slate-500 hover:text-slate-200 hover:bg-slate-700 transition-colors"
                        title="Edit env file"
                      >
                        <Pencil size={12} />
                      </button>
                    </div>
                  )}
                </div>
              )}

              {service.ports.length > 0 && (
                <div>
                  <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">Ports</span>
                  <div className="flex flex-wrap gap-1.5">
                    {service.ports.map((p, i) => (
                      <a
                        key={i}
                        href={`http://${window.location.hostname}:${p.host}`}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="inline-flex items-center gap-1.5 text-sm font-mono bg-slate-800/80 text-cyan-300 px-2.5 py-1 rounded hover:bg-slate-700/80 hover:text-cyan-200 transition-colors cursor-pointer"
                        title={`Open http://${window.location.hostname}:${p.host}`}
                      >
                        <Globe size={13} className="text-slate-500" />
                        {p.host} → {p.container}
                        <ExternalLink size={11} className="text-slate-500" />
                      </a>
                    ))}
                  </div>
                </div>
              )}

              {service.networks.length > 0 && (
                <div>
                  <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">Networks</span>
                  <div className="flex flex-wrap gap-1.5">
                    {service.networks.map((n, i) => (
                      <span key={i} className="inline-flex items-center gap-1.5 text-sm font-mono bg-slate-800/80 text-purple-300 px-2.5 py-1 rounded">
                        <Network size={13} className="text-slate-500" />
                        {n}
                        {service.network_ips?.[n] && (
                          <span className="text-slate-500 ml-1">{service.network_ips[n]}</span>
                        )}
                      </span>
                    ))}
                  </div>
                </div>
              )}

              {/* Connected services */}
              {connectedSvcs.length > 0 && (
                  <div>
                    <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">Connected to</span>
                    <div className="flex flex-wrap gap-1.5">
                      {connectedSvcs.map((s) => {
                        const dotColor = s.state === "running" ? "bg-emerald-400" : s.state === "exited" || s.state === "dead" ? "bg-red-400" : "bg-yellow-400";
                        return (
                          <span key={s.uid} className="inline-flex items-center gap-1.5 text-sm bg-slate-800/80 text-slate-300 px-2.5 py-1 rounded">
                            <span className={`w-1.5 h-1.5 rounded-full ${dotColor}`} />
                            {s.name}
                          </span>
                        );
                      })}
                    </div>
                  </div>
              )}
            </div>
          )}

        {/* Config tab */}
        {activeTab === "config" && (
          <div className="flex-1 overflow-y-auto px-4 py-3 space-y-3">
            {/* Restart policy */}
            {service.restart_policy && (
              <DetailRow label="Restart Policy" value={service.restart_policy} />
            )}

            {/* Resource limits */}
            <div>
              <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">Resource Limits</span>
              <div className="grid grid-cols-2 gap-2">
                <div className="bg-slate-800/80 rounded px-3 py-2">
                  <span className="text-[11px] uppercase tracking-wider text-slate-500 block">Memory Limit</span>
                  <span className="text-xs font-mono text-slate-200">
                    {service.memory_limit > 0
                      ? `${(service.memory_limit / 1024 / 1024).toFixed(0)} MB`
                      : "Unlimited"}
                  </span>
                </div>
                <div className="bg-slate-800/80 rounded px-3 py-2">
                  <span className="text-[11px] uppercase tracking-wider text-slate-500 block">CPU Quota</span>
                  <span className="text-xs font-mono text-slate-200">
                    {service.cpu_quota > 0
                      ? `${(service.cpu_quota / 1000).toFixed(0)}%`
                      : "Unlimited"}
                  </span>
                </div>
              </div>
            </div>

            {/* Health check */}
            <div>
              <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">Health Check</span>
              {service.health_status ? (
                <div className="space-y-2">
                  <span className={`inline-flex items-center gap-1.5 text-xs font-mono px-2 py-0.5 rounded ${
                    service.health_status === "healthy" ? "bg-emerald-900/40 text-emerald-400" :
                    service.health_status === "unhealthy" ? "bg-red-900/40 text-red-400" :
                    "bg-yellow-900/40 text-yellow-400"
                  }`}>
                    <span className={`w-1.5 h-1.5 rounded-full ${
                      service.health_status === "healthy" ? "bg-emerald-400" :
                      service.health_status === "unhealthy" ? "bg-red-400" :
                      "bg-yellow-400"
                    }`} />
                    {service.health_status}
                  </span>
                  {service.health_log.length > 0 && (
                    <div className="bg-slate-800/60 rounded p-2 space-y-0.5">
                      <span className="text-[10px] text-slate-500 block mb-1">Recent checks</span>
                      {service.health_log.map((entry, i) => (
                        <div key={i} className="text-[11px] font-mono text-slate-400 break-all">{entry}</div>
                      ))}
                    </div>
                  )}
                </div>
              ) : (
                <span className="text-xs text-slate-500">Not configured</span>
              )}
            </div>
          </div>
        )}

        {/* Env tab */}
        {activeTab === "env" && (() => {
          const filteredEnv = (service.env || []).filter((entry) => {
            const key = entry.split("=")[0];
            return !SYSTEM_ENV_KEYS.has(key);
          });
          return (
          <div className="flex-1 overflow-y-auto px-4 py-3">
            <div className="flex items-center justify-between mb-2">
              <span className="text-[11px] uppercase tracking-wider text-slate-500">{filteredEnv.length} variables</span>
              <div className="flex items-center gap-1">
                <button
                  onClick={() => {
                    const text = filteredEnv.join("\n");
                    try {
                      navigator.clipboard.writeText(text);
                    } catch {
                      const ta = document.createElement("textarea");
                      ta.value = text;
                      ta.style.position = "fixed";
                      ta.style.opacity = "0";
                      document.body.appendChild(ta);
                      ta.select();
                      document.execCommand("copy");
                      document.body.removeChild(ta);
                    }
                    setCopiedEnvIdx(-1);
                    setTimeout(() => setCopiedEnvIdx(null), 1500);
                  }}
                  className="flex items-center gap-1.5 px-2 py-1 rounded text-[10px] font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-800 transition-colors"
                >
                  {copiedEnvIdx === -1 ? <Check size={11} className="text-emerald-400" /> : <Copy size={11} />}
                  {copiedEnvIdx === -1 ? "Copied!" : "Copy all"}
                </button>
                <button
                  onClick={() => { setEnvVisibleAll((v) => !v); setEnvVisibleSet(new Set()); }}
                  className="flex items-center gap-1.5 px-2 py-1 rounded text-[10px] font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-800 transition-colors"
                >
                  {envVisibleAll ? <EyeOff size={11} /> : <Eye size={11} />}
                  {envVisibleAll ? "Hide all" : "Show all"}
                </button>
              </div>
            </div>
            {filteredEnv.length > 0 ? (
              <div className="space-y-0.5">
                {filteredEnv.map((entry, i) => {
                  const eqIdx = entry.indexOf("=");
                  const key = eqIdx >= 0 ? entry.slice(0, eqIdx) : entry;
                  const val = eqIdx >= 0 ? entry.slice(eqIdx + 1) : "";
                  return (
                    <div key={i} className="group flex items-center gap-0 font-mono text-xs py-1.5 hover:bg-slate-800/40 rounded px-1">
                      {(() => {
                        const isVisible = envVisibleAll || envVisibleSet.has(i);
                        return (
                          <>
                            <span className="text-cyan-400 shrink-0">{key}</span>
                            <span className="text-slate-600 mx-1">=</span>
                            <span className={`break-all flex-1 ${isVisible ? "text-slate-300" : "text-slate-600 select-none"}`}>
                              {isVisible ? val : "••••••••"}
                            </span>
                            <button
                              onClick={() => setEnvVisibleSet((prev) => {
                                const next = new Set(prev);
                                if (next.has(i)) next.delete(i); else next.add(i);
                                return next;
                              })}
                              className="shrink-0 ml-2 p-1 rounded opacity-0 group-hover:opacity-100 text-slate-500 hover:text-slate-200 transition-opacity"
                              title={isVisible ? "Hide" : "Show"}
                            >
                              {isVisible ? <EyeOff size={15} /> : <Eye size={15} />}
                            </button>
                            <button
                              onClick={() => {
                                try {
                                  navigator.clipboard.writeText(entry);
                                } catch {
                                  // Fallback for non-HTTPS
                                  const ta = document.createElement("textarea");
                                  ta.value = entry;
                                  ta.style.position = "fixed";
                                  ta.style.opacity = "0";
                                  document.body.appendChild(ta);
                                  ta.select();
                                  document.execCommand("copy");
                                  document.body.removeChild(ta);
                                }
                                setCopiedEnvIdx(i);
                                setTimeout(() => setCopiedEnvIdx(null), 1500);
                              }}
                              className="shrink-0 ml-1 p-1 rounded opacity-0 group-hover:opacity-100 text-slate-500 hover:text-slate-200 transition-opacity"
                              title="Copy"
                            >
                              {copiedEnvIdx === i ? <Check size={15} className="text-emerald-400" /> : <Copy size={15} />}
                            </button>
                          </>
                        );
                      })()}
                    </div>
                  );
                })}
              </div>
            ) : (
              <div className="text-slate-500 text-sm text-center py-8">No environment variables available</div>
            )}
          </div>
          );
        })()}

        {/* Stats tab */}
        {activeTab === "stats" && (
          <div className="flex-1 overflow-y-auto px-4 py-3 space-y-4">
            {stats ? (
              <>
                <div className="grid grid-cols-2 gap-3">
                  <StatCard label="CPU" value={`${stats.cpu.toFixed(1)}%`} color={stats.cpu > 80 ? "text-red-400" : stats.cpu > 50 ? "text-yellow-400" : "text-emerald-400"} />
                  <StatCard label="Memory" value={`${stats.mem_mb.toFixed(0)} MB`} extra={`${stats.mem_percent.toFixed(1)}%`} color={stats.mem_percent > 80 ? "text-red-400" : stats.mem_percent > 50 ? "text-yellow-400" : "text-emerald-400"} />
                </div>

                {/* CPU bar */}
                <div>
                  <div className="flex justify-between text-xs text-slate-500 mb-1">
                    <span>CPU Usage</span>
                    <span>{stats.cpu.toFixed(1)}%</span>
                  </div>
                  <div className="h-2 bg-slate-800 rounded-full overflow-hidden">
                    <div
                      className={`h-full rounded-full transition-all duration-500 ${stats.cpu > 80 ? "bg-red-500" : stats.cpu > 50 ? "bg-yellow-500" : "bg-emerald-500"}`}
                      style={{ width: `${Math.min(stats.cpu, 100)}%` }}
                    />
                  </div>
                </div>

                {/* Memory bar */}
                <div>
                  <div className="flex justify-between text-xs text-slate-500 mb-1">
                    <span>Memory Usage</span>
                    <span>{stats.mem_mb.toFixed(0)} MB ({stats.mem_percent.toFixed(1)}%)</span>
                  </div>
                  <div className="h-2 bg-slate-800 rounded-full overflow-hidden">
                    <div
                      className={`h-full rounded-full transition-all duration-500 ${stats.mem_percent > 80 ? "bg-red-500" : stats.mem_percent > 50 ? "bg-yellow-500" : "bg-emerald-500"}`}
                      style={{ width: `${Math.min(stats.mem_percent, 100)}%` }}
                    />
                  </div>
                </div>
              </>
            ) : (
              <div className="text-slate-500 text-sm text-center py-8">No stats available</div>
            )}
          </div>
        )}

        </div>

        {/* Logs section — always visible at bottom */}
        <div className="flex-1 min-h-0 flex flex-col">
          {/* Expand/collapse divider */}
          <div className="relative shrink-0">
            <div className="border-t border-slate-700/60" />
            <div className="absolute inset-x-0 -top-3 flex justify-center">
              <button
                onClick={() => {
                  setLogsExpanded((v) => !v);
                  // Scroll to bottom during and after transition
                  const scrollToBottom = () => {
                    if (scrollRef.current) {
                      programmaticScroll.current = true;
                      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
                    }
                  };
                  scrollToBottom();
                  setTimeout(scrollToBottom, 50);
                  setTimeout(scrollToBottom, 150);
                  setTimeout(scrollToBottom, 300);
                  setTimeout(scrollToBottom, 350);
                }}
                className="flex items-center gap-1.5 px-3 py-0.5 rounded-full bg-slate-800 border border-slate-700/60 text-slate-400 hover:text-slate-200 hover:bg-slate-700 transition-colors text-[10px] font-medium"
                title={logsExpanded ? "Collapse logs" : "Expand logs"}
              >
                {logsExpanded ? <ChevronDown size={10} /> : <ChevronUp size={10} />}
                {logsExpanded ? "Collapse" : "Expand"}
              </button>
            </div>
          </div>
          <div className="flex items-center justify-between px-4 py-2 shrink-0">
            <div className="flex items-center gap-2">
              <Terminal size={14} className="text-cyan-400" />
              <span className="text-sm font-medium text-slate-300">Logs</span>
              {service.state === "running" && subscribedRef.current && (
                <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
              )}
            </div>
            <div className="flex items-center gap-1">
              {service.state === "running" && (
                <button
                  onClick={() => { setExecOpen((v) => { if (!v) setLogsExpanded(true); return !v; }); setExecResult(null); setExecError(null); }}
                  className={`flex items-center gap-1 px-2 py-0.5 rounded text-[11px] font-medium transition-colors ${execOpen ? "text-purple-300 bg-purple-400/10" : "text-purple-400 hover:bg-purple-400/10"}`}
                  title="Exec command"
                >
                  <Terminal size={12} />
                  Exec
                </button>
              )}
              <button
                onClick={() => {
                  setAutoScroll((v) => {
                    if (v) manualPause.current = true;
                    else manualPause.current = false;
                    return !v;
                  });
                }}
                className="p-1 rounded hover:bg-slate-700/60 text-slate-400 hover:text-slate-200 transition-colors"
                title={autoScroll ? "Pause auto-scroll" : "Resume auto-scroll"}
              >
                {autoScroll ? <Pause size={12} /> : <Play size={12} />}
              </button>
              <button
                onClick={() => startTransition(() => setLogsModal(true))}
                className="p-1 rounded hover:bg-slate-700/60 text-slate-400 hover:text-slate-200 transition-colors"
                title="Open logs fullscreen"
              >
                <Maximize2 size={12} />
              </button>
            </div>
          </div>
          {/* Exec panel — below logs header */}
          {execOpen && (
            <div className="px-4 py-2.5 bg-slate-800/90 border-b border-slate-700/60 shrink-0 space-y-2">
              <div className="flex items-center gap-2">
                <input
                  type="text"
                  value={execCmd}
                  onChange={(e) => setExecCmd(e.target.value)}
                  onKeyDown={(e) => {
                    if (e.key === "Enter" && execCmd.trim() && !execLoading) {
                      e.preventDefault();
                      runExec();
                    }
                  }}
                  placeholder="e.g. python manage.py migrate"
                  className="flex-1 bg-slate-900 border border-slate-600 rounded px-2.5 py-1.5 text-xs font-mono text-slate-200 placeholder:text-slate-600 focus:outline-none focus:border-purple-500"
                  autoFocus
                />
                <button
                  onClick={runExec}
                  disabled={!execCmd.trim() || execLoading}
                  className="px-3 py-1.5 rounded text-[11px] font-medium text-white bg-purple-700 hover:bg-purple-600 transition-colors disabled:opacity-40"
                >
                  {execLoading ? <Loader2 size={12} className="animate-spin" /> : "Run"}
                </button>
                <button
                  onClick={() => { setExecOpen(false); setExecResult(null); setExecError(null); }}
                  className="p-1 rounded text-slate-400 hover:text-slate-200 hover:bg-slate-700 transition-colors"
                  title="Close"
                >
                  <X size={14} />
                </button>
              </div>
              {execError && (
                <div className="text-xs text-red-400 bg-red-900/20 border border-red-800/40 rounded px-2.5 py-1.5">{execError}</div>
              )}
              {execResult && (
                <div className="space-y-1">
                  <div className="flex items-center gap-2 text-[11px]">
                    <span className={execResult.exitCode === 0 ? "text-emerald-400" : "text-red-400"}>
                      Exit code: {execResult.exitCode}
                    </span>
                  </div>
                  <pre className="bg-slate-900 rounded px-2.5 py-2 text-xs font-mono text-slate-300 max-h-48 overflow-auto whitespace-pre-wrap break-all">{execResult.output || "(no output)"}</pre>
                </div>
              )}
            </div>
          )}
          <div
            ref={scrollRef}
            onScroll={handleScroll}
            className="flex-1 overflow-y-auto overflow-x-hidden font-mono text-xs leading-5 px-3 py-2"
          >
            {loading && (
              <div className="text-slate-500 py-4 text-center">Loading logs...</div>
            )}
            {!loading && allLines.length === 0 && (
              <div className="text-slate-500 py-4 text-center">No logs available</div>
            )}
            {allLines.map((l, i) => (
              <div key={i} className="flex gap-0 hover:bg-slate-800/40">
                {l.timestamp && (
                  <span className="text-slate-600 shrink-0 select-none pr-2 whitespace-nowrap">
                    {formatTimestamp(l.timestamp)}
                  </span>
                )}
                <span className={`whitespace-pre truncate ${logLineColor(l)}`}>
                  {l.line}
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>

      {/* Logs fullscreen modal */}
      {logsModal && (
        <div className="fixed inset-0 z-[100] bg-slate-900 flex flex-col">
          <div className="flex items-center justify-between px-6 py-3 border-b border-slate-800 shrink-0">
            <div className="flex items-center gap-2.5">
              <Terminal size={16} className="text-cyan-400" />
              <span className="text-sm font-semibold text-white">{service.name}</span>
              <span className="text-xs text-slate-500 font-mono">logs</span>
              {service.state === "running" && subscribedRef.current && (
                <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
              )}
            </div>
            <div className="flex items-center gap-1">
              <button
                onClick={() => {
                  const text = allLines.map((l) => `${l.timestamp ? formatTimestamp(l.timestamp) + " " : ""}${l.line}`).join("\n");
                  try {
                    navigator.clipboard.writeText(text);
                  } catch {
                    const ta = document.createElement("textarea");
                    ta.value = text;
                    ta.style.position = "fixed";
                    ta.style.opacity = "0";
                    document.body.appendChild(ta);
                    ta.select();
                    document.execCommand("copy");
                    document.body.removeChild(ta);
                  }
                  setCopiedEnvIdx(-99);
                  setTimeout(() => setCopiedEnvIdx(null), 1500);
                }}
                className="p-1.5 rounded hover:bg-slate-700/60 text-slate-400 hover:text-slate-200 transition-colors"
                title="Copy all logs"
              >
                {copiedEnvIdx === -99 ? <Check size={16} className="text-emerald-400" /> : <Copy size={16} />}
              </button>
              <button
                onClick={() => setLogsModal(false)}
                className="p-1.5 rounded hover:bg-slate-700/60 text-slate-400 hover:text-slate-200 transition-colors"
              >
                <X size={16} />
              </button>
            </div>
          </div>
          <div
            ref={modalScrollRef}
            className="flex-1 overflow-y-auto overflow-x-auto font-mono text-xs leading-5 px-6 py-3"
          >
            {allLines.length > 500 && (
              <div className="text-slate-600 text-center py-2 text-[11px]">
                {allLines.length - 500} lines hidden
              </div>
            )}
            {(allLines.length > 500 ? allLines.slice(-500) : allLines).map((l, i) => (
              <div key={i} className="flex gap-0 hover:bg-slate-800/40">
                {l.timestamp && (
                  <span className="text-slate-600 shrink-0 select-none pr-3 whitespace-nowrap">
                    {formatTimestamp(l.timestamp)}
                  </span>
                )}
                <span className={`whitespace-pre-wrap break-all ${logLineColor(l)}`}>
                  {l.line}
                </span>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

const ERROR_PATTERN = /\b(error|fatal|critical|exception|traceback|panic|failed|segfault)\b/i;
const WARN_PATTERN = /\b(warn|warning)\b/i;

function logLineColor(l: LogLine): string {
  if (l.line.startsWith("[DOCKER]")) return "text-cyan-400 font-semibold";
  if (ERROR_PATTERN.test(l.line)) return "text-red-400";
  if (WARN_PATTERN.test(l.line)) return "text-yellow-400";
  return "text-slate-400";
}

function DetailRow({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div>
      <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-0.5">{label}</span>
      <span className={`text-sm text-slate-200 ${mono ? "font-mono" : ""} break-all`}>{value}</span>
    </div>
  );
}

function StatCard({ label, value, extra, color }: { label: string; value: string; extra?: string; color: string }) {
  return (
    <div className="bg-slate-800/80 rounded-lg px-4 py-3">
      <span className="text-[11px] uppercase tracking-wider text-slate-500 block mb-1">{label}</span>
      <span className={`text-xl font-mono font-semibold ${color}`}>{value}</span>
      {extra && <span className="text-xs text-slate-500 ml-2">{extra}</span>}
    </div>
  );
}

function formatTimestamp(ts: string): string {
  try {
    const d = new Date(ts);
    return d.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
  } catch {
    return ts.slice(11, 19);
  }
}
