"use client";

import { useState, useEffect, useCallback, useRef } from "react";
import type { ReactElement } from "react";

import { MosaicSpinner } from "@/components/ui/MosaicSpinner";
import { fetchRunnerJobs, fetchJobSteps, RunnerJobStatus } from "@/lib/api/runner-jobs";
import type { RunnerJob, JobStep } from "@/lib/api/runner-jobs";
import { useWorkspaceId } from "@/lib/hooks";

// ─── Constants ────────────────────────────────────────────────────────

type StatusFilter = "all" | "running" | "completed" | "failed" | "queued";
type DateRange = "24h" | "7d" | "30d" | "all";

const STATUS_OPTIONS: { value: StatusFilter; label: string }[] = [
  { value: "all", label: "All statuses" },
  { value: "running", label: "Running" },
  { value: "completed", label: "Completed" },
  { value: "failed", label: "Failed" },
  { value: "queued", label: "Queued" },
];

const DATE_RANGES: { value: DateRange; label: string }[] = [
  { value: "24h", label: "Last 24h" },
  { value: "7d", label: "7d" },
  { value: "30d", label: "30d" },
  { value: "all", label: "All" },
];

const STATUS_FILTER_TO_ENUM: Record<StatusFilter, RunnerJobStatus[] | undefined> = {
  all: undefined,
  running: [RunnerJobStatus.RUNNING],
  completed: [RunnerJobStatus.COMPLETED],
  failed: [RunnerJobStatus.FAILED],
  queued: [RunnerJobStatus.QUEUED, RunnerJobStatus.PENDING],
};

const POLL_INTERVAL_MS = 5_000;

// ─── Helpers ──────────────────────────────────────────────────────────

function getStatusColor(status: string): string {
  switch (status) {
    case "RUNNING":
      return "var(--ms-amber-400)";
    case "COMPLETED":
      return "var(--ms-teal-400)";
    case "FAILED":
    case "CANCELLED":
      return "var(--danger)";
    case "QUEUED":
    case "PENDING":
      return "var(--ms-blue-400)";
    default:
      return "var(--muted)";
  }
}

function formatRelativeTime(dateStr: string | null): string {
  if (!dateStr) return "\u2014";
  const date = new Date(dateStr);
  const now = Date.now();
  const diffMs = now - date.getTime();
  const diffSec = Math.floor(diffMs / 1_000);
  const diffMin = Math.floor(diffSec / 60);
  const diffHr = Math.floor(diffMin / 60);
  const diffDay = Math.floor(diffHr / 24);

  if (diffSec < 60) return "just now";
  if (diffMin < 60) return `${String(diffMin)}m ago`;
  if (diffHr < 24) return `${String(diffHr)}h ago`;
  if (diffDay < 30) return `${String(diffDay)}d ago`;
  return date.toLocaleDateString();
}

function formatDuration(startedAt: string | null, completedAt: string | null): string {
  if (!startedAt) return "\u2014";
  const start = new Date(startedAt).getTime();
  const end = completedAt ? new Date(completedAt).getTime() : Date.now();
  const ms = end - start;
  if (ms < 1_000) return `${String(ms)}ms`;
  const sec = Math.floor(ms / 1_000);
  if (sec < 60) return `${String(sec)}s`;
  const min = Math.floor(sec / 60);
  const remainSec = sec % 60;
  return `${String(min)}m ${String(remainSec)}s`;
}

function formatStepDuration(durationMs: number | null): string {
  if (durationMs === null) return "\u2014";
  if (durationMs < 1_000) return `${String(durationMs)}ms`;
  const sec = Math.floor(durationMs / 1_000);
  if (sec < 60) return `${String(sec)}s`;
  const min = Math.floor(sec / 60);
  const remainSec = sec % 60;
  return `${String(min)}m ${String(remainSec)}s`;
}

function isWithinDateRange(dateStr: string, range: DateRange): boolean {
  if (range === "all") return true;
  const date = new Date(dateStr);
  const now = Date.now();
  const hours = range === "24h" ? 24 : range === "7d" ? 168 : 720;
  return now - date.getTime() < hours * 60 * 60 * 1_000;
}

// ─── Status Badge ─────────────────────────────────────────────────────

function StatusBadge({ status }: { status: string }): ReactElement {
  const color = getStatusColor(status);
  const isRunning = status === "RUNNING";

  return (
    <span
      style={{
        display: "inline-flex",
        alignItems: "center",
        gap: 6,
        padding: "2px 10px",
        borderRadius: 9999,
        fontSize: "0.75rem",
        fontWeight: 600,
        color,
        background: `color-mix(in srgb, ${color} 15%, transparent)`,
        border: `1px solid color-mix(in srgb, ${color} 30%, transparent)`,
        textTransform: "capitalize",
      }}
    >
      {isRunning && (
        <span
          style={{
            width: 6,
            height: 6,
            borderRadius: "50%",
            background: color,
            animation: "pulse 1.5s ease-in-out infinite",
          }}
        />
      )}
      {status.toLowerCase()}
    </span>
  );
}

// ─── Main Page Component ──────────────────────────────────────────────

export default function LogsPage(): ReactElement {
  const workspaceId = useWorkspaceId();

  // Data state
  const [jobs, setJobs] = useState<RunnerJob[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // Expanded job and steps
  const [expandedJobId, setExpandedJobId] = useState<string | null>(null);
  const [jobStepsMap, setJobStepsMap] = useState<Record<string, JobStep[]>>({});
  const [stepsLoading, setStepsLoading] = useState<Set<string>>(new Set());

  // Filters
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
  const [dateRange, setDateRange] = useState<DateRange>("7d");
  const [searchQuery, setSearchQuery] = useState("");

  // Auto-refresh
  const [autoRefresh, setAutoRefresh] = useState(false);
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);

  // Hover state
  const [hoveredRowId, setHoveredRowId] = useState<string | null>(null);

  // ─── Data Loading ─────────────────────────────────────────────────

  const loadJobs = useCallback(async (): Promise<void> => {
    try {
      const statusEnums = STATUS_FILTER_TO_ENUM[statusFilter];
      const filters: Parameters<typeof fetchRunnerJobs>[0] = {};
      if (workspaceId) {
        filters.workspaceId = workspaceId;
      }
      if (statusEnums) {
        filters.status = statusEnums;
      }

      const data = await fetchRunnerJobs(filters);
      setJobs(data);
      setError(null);
    } catch (err: unknown) {
      console.error("[Logs] Failed to fetch runner jobs:", err);
      setError(
        err instanceof Error
          ? err.message
          : "We had trouble loading jobs. Please try again when you're ready."
      );
    }
  }, [workspaceId, statusFilter]);

  // Initial load
  useEffect(() => {
    let cancelled = false;
    setIsLoading(true);

    loadJobs()
      .then(() => {
        if (!cancelled) {
          setIsLoading(false);
        }
      })
      .catch(() => {
        if (!cancelled) {
          setIsLoading(false);
        }
      });

    return (): void => {
      cancelled = true;
    };
  }, [loadJobs]);

  // Auto-refresh polling
  useEffect(() => {
    if (autoRefresh) {
      intervalRef.current = setInterval(() => {
        void loadJobs();
      }, POLL_INTERVAL_MS);
    } else if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }

    return (): void => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
    };
  }, [autoRefresh, loadJobs]);

  // ─── Steps Loading ────────────────────────────────────────────────

  const toggleExpand = useCallback(
    (jobId: string) => {
      if (expandedJobId === jobId) {
        setExpandedJobId(null);
        return;
      }

      setExpandedJobId(jobId);

      // Load steps if not already loaded
      if (!jobStepsMap[jobId] && !stepsLoading.has(jobId)) {
        setStepsLoading((prev) => new Set(prev).add(jobId));

        fetchJobSteps(jobId, workspaceId ?? undefined)
          .then((steps) => {
            setJobStepsMap((prev) => ({ ...prev, [jobId]: steps }));
          })
          .catch((err: unknown) => {
            console.error("[Logs] Failed to fetch steps for job:", jobId, err);
            setJobStepsMap((prev) => ({ ...prev, [jobId]: [] }));
          })
          .finally(() => {
            setStepsLoading((prev) => {
              const next = new Set(prev);
              next.delete(jobId);
              return next;
            });
          });
      }
    },
    [expandedJobId, jobStepsMap, stepsLoading, workspaceId]
  );

  // ─── Filtering ────────────────────────────────────────────────────

  const filteredJobs = jobs.filter((job) => {
    // Date range filter
    if (!isWithinDateRange(job.createdAt, dateRange)) return false;

    // Search filter
    if (searchQuery.trim()) {
      const q = searchQuery.toLowerCase();
      const matchesType = job.type.toLowerCase().includes(q);
      const matchesId = job.id.toLowerCase().includes(q);
      if (!matchesType && !matchesId) return false;
    }

    return true;
  });

  // ─── Manual Refresh ───────────────────────────────────────────────

  const handleManualRefresh = (): void => {
    setIsLoading(true);
    void loadJobs().finally(() => {
      setIsLoading(false);
    });
  };

  const handleRetry = (): void => {
    setError(null);
    handleManualRefresh();
  };

  // ─── Render ───────────────────────────────────────────────────────

  return (
    <main className="container mx-auto px-4 py-8">
      {/* Pulse animation for running status */}
      <style>{`
        @keyframes pulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.4; }
        }
        @keyframes auto-refresh-spin {
          from { transform: rotate(0deg); }
          to { transform: rotate(360deg); }
        }
      `}</style>

      {/* ─── Header ─────────────────────────────────────────────── */}
      <div
        style={{
          display: "flex",
          flexWrap: "wrap",
          alignItems: "center",
          justifyContent: "space-between",
          gap: 16,
          marginBottom: 32,
        }}
      >
        <div>
          <h1 className="text-3xl font-bold" style={{ color: "var(--text)" }}>
            Logs &amp; Telemetry
          </h1>
          <p className="mt-1" style={{ color: "var(--text-muted)" }}>
            Runner job history and step-level detail
          </p>
        </div>

        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          {/* Auto-refresh toggle */}
          <button
            onClick={() => {
              setAutoRefresh((prev) => !prev);
            }}
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: 8,
              padding: "8px 14px",
              borderRadius: 8,
              fontSize: "0.82rem",
              fontWeight: 500,
              cursor: "pointer",
              border: `1px solid ${autoRefresh ? "var(--ms-teal-400)" : "var(--border)"}`,
              background: autoRefresh
                ? "color-mix(in srgb, var(--ms-teal-400) 12%, transparent)"
                : "var(--surface)",
              color: autoRefresh ? "var(--ms-teal-400)" : "var(--text-muted)",
              transition: "all 150ms ease",
            }}
          >
            {autoRefresh && (
              <span
                style={{
                  width: 8,
                  height: 8,
                  borderRadius: "50%",
                  background: "var(--ms-teal-400)",
                  animation: "pulse 1.5s ease-in-out infinite",
                }}
              />
            )}
            Auto-refresh {autoRefresh ? "on" : "off"}
          </button>

          {/* Manual refresh */}
          <button
            onClick={handleManualRefresh}
            disabled={isLoading}
            style={{
              padding: "8px 14px",
              borderRadius: 8,
              fontSize: "0.82rem",
              fontWeight: 500,
              cursor: isLoading ? "not-allowed" : "pointer",
              border: "1px solid var(--border)",
              background: "var(--surface)",
              color: "var(--text-muted)",
              opacity: isLoading ? 0.5 : 1,
              transition: "all 150ms ease",
            }}
          >
            Refresh
          </button>
        </div>
      </div>

      {/* ─── Filter Bar ─────────────────────────────────────────── */}
      <div
        style={{
          display: "flex",
          flexWrap: "wrap",
          alignItems: "center",
          gap: 12,
          marginBottom: 24,
        }}
      >
        {/* Status filter */}
        <select
          value={statusFilter}
          onChange={(e) => {
            setStatusFilter(e.target.value as StatusFilter);
          }}
          style={{
            padding: "8px 12px",
            borderRadius: 8,
            fontSize: "0.82rem",
            border: "1px solid var(--border)",
            background: "var(--surface)",
            color: "var(--text)",
            cursor: "pointer",
            minWidth: 140,
          }}
        >
          {STATUS_OPTIONS.map((opt) => (
            <option key={opt.value} value={opt.value}>
              {opt.label}
            </option>
          ))}
        </select>

        {/* Date range tabs */}
        <div
          style={{
            display: "flex",
            borderRadius: 8,
            overflow: "hidden",
            border: "1px solid var(--border)",
          }}
        >
          {DATE_RANGES.map((range) => (
            <button
              key={range.value}
              onClick={() => {
                setDateRange(range.value);
              }}
              style={{
                padding: "8px 14px",
                fontSize: "0.82rem",
                fontWeight: 500,
                cursor: "pointer",
                border: "none",
                borderRight: "1px solid var(--border)",
                background: dateRange === range.value ? "var(--primary)" : "var(--surface)",
                color: dateRange === range.value ? "#fff" : "var(--text-muted)",
                transition: "all 150ms ease",
              }}
            >
              {range.label}
            </button>
          ))}
        </div>

        {/* Search input */}
        <input
          type="text"
          placeholder="Search by job type..."
          value={searchQuery}
          onChange={(e) => {
            setSearchQuery(e.target.value);
          }}
          style={{
            padding: "8px 12px",
            borderRadius: 8,
            fontSize: "0.82rem",
            border: "1px solid var(--border)",
            background: "var(--surface)",
            color: "var(--text)",
            minWidth: 200,
            flex: "1 1 200px",
            maxWidth: 320,
          }}
        />
      </div>

      {/* ─── Content ────────────────────────────────────────────── */}
      {isLoading && jobs.length === 0 ? (
        <div className="flex justify-center py-16">
          <MosaicSpinner label="Loading jobs..." />
        </div>
      ) : error !== null ? (
        <div
          className="rounded-lg p-6 text-center"
          style={{
            background: "var(--surface)",
            border: "1px solid var(--border)",
          }}
        >
          <p style={{ color: "var(--danger)" }}>{error}</p>
          <button
            onClick={handleRetry}
            className="mt-4 rounded-md px-4 py-2 text-sm font-medium text-white transition-colors"
            style={{ background: "var(--danger)", cursor: "pointer", border: "none" }}
          >
            Try again
          </button>
        </div>
      ) : filteredJobs.length === 0 ? (
        <div
          className="rounded-lg p-8 text-center"
          style={{
            background: "var(--surface)",
            border: "1px solid var(--border)",
          }}
        >
          <p style={{ color: "var(--text-muted)" }}>No jobs found</p>
        </div>
      ) : (
        /* ─── Job Table ──────────────────────────────────────────── */
        <div
          style={{
            borderRadius: 12,
            border: "1px solid var(--border)",
            overflow: "hidden",
          }}
        >
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse" }}>
              <thead>
                <tr
                  style={{
                    background: "var(--bg-mid)",
                  }}
                >
                  {["Job Type", "Status", "Started", "Duration", "Steps"].map((header) => (
                    <th
                      key={header}
                      style={{
                        padding: "10px 16px",
                        textAlign: "left",
                        fontSize: "0.75rem",
                        fontWeight: 600,
                        textTransform: "uppercase",
                        letterSpacing: "0.05em",
                        color: "var(--muted)",
                        fontFamily: "var(--mono)",
                        whiteSpace: "nowrap",
                      }}
                    >
                      {header}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {filteredJobs.map((job) => {
                  const isExpanded = expandedJobId === job.id;
                  const isHovered = hoveredRowId === job.id;
                  const steps = jobStepsMap[job.id];
                  const isStepsLoading = stepsLoading.has(job.id);

                  return (
                    <JobRow
                      key={job.id}
                      job={job}
                      isExpanded={isExpanded}
                      isHovered={isHovered}
                      steps={steps}
                      isStepsLoading={isStepsLoading}
                      onToggle={() => {
                        toggleExpand(job.id);
                      }}
                      onMouseEnter={() => {
                        setHoveredRowId(job.id);
                      }}
                      onMouseLeave={() => {
                        setHoveredRowId(null);
                      }}
                    />
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </main>
  );
}

// ─── Job Row Component ────────────────────────────────────────────────

function JobRow({
  job,
  isExpanded,
  isHovered,
  steps,
  isStepsLoading,
  onToggle,
  onMouseEnter,
  onMouseLeave,
}: {
  job: RunnerJob;
  isExpanded: boolean;
  isHovered: boolean;
  steps: JobStep[] | undefined;
  isStepsLoading: boolean;
  onToggle: () => void;
  onMouseEnter: () => void;
  onMouseLeave: () => void;
}): ReactElement {
  return (
    <>
      <tr
        onClick={onToggle}
        onMouseEnter={onMouseEnter}
        onMouseLeave={onMouseLeave}
        style={{
          background: isExpanded
            ? "var(--surface-2)"
            : isHovered
              ? "var(--surface-2)"
              : "var(--surface)",
          cursor: "pointer",
          borderBottom: isExpanded ? "none" : "1px solid var(--border)",
          transition: "background 100ms ease",
        }}
      >
        <td
          style={{
            padding: "12px 16px",
            fontSize: "0.85rem",
            fontWeight: 500,
            color: "var(--text)",
            whiteSpace: "nowrap",
          }}
        >
          <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
            <span
              style={{
                display: "inline-block",
                width: 16,
                textAlign: "center",
                fontSize: "0.7rem",
                color: "var(--muted)",
                transition: "transform 150ms ease",
                transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
              }}
            >
              &#9654;
            </span>
            {job.type}
          </span>
        </td>
        <td style={{ padding: "12px 16px" }}>
          <StatusBadge status={job.status} />
        </td>
        <td
          style={{
            padding: "12px 16px",
            fontSize: "0.82rem",
            fontFamily: "var(--mono)",
            color: "var(--text-muted)",
            whiteSpace: "nowrap",
          }}
        >
          {formatRelativeTime(job.startedAt ?? job.createdAt)}
        </td>
        <td
          style={{
            padding: "12px 16px",
            fontSize: "0.82rem",
            fontFamily: "var(--mono)",
            color: "var(--text-muted)",
            whiteSpace: "nowrap",
          }}
        >
          {formatDuration(job.startedAt, job.completedAt)}
        </td>
        <td
          style={{
            padding: "12px 16px",
            fontSize: "0.82rem",
            fontFamily: "var(--mono)",
            color: "var(--text-muted)",
          }}
        >
          {steps ? String(steps.length) : "\u2014"}
        </td>
      </tr>

      {/* Expanded Steps Section */}
      {isExpanded && (
        <tr>
          <td
            colSpan={5}
            style={{
              padding: 0,
              borderBottom: "1px solid var(--border)",
            }}
          >
            <div
              style={{
                background: "var(--bg-mid)",
                padding: "12px 16px 12px 48px",
              }}
            >
              {isStepsLoading ? (
                <div style={{ display: "flex", justifyContent: "center", padding: 16 }}>
                  <MosaicSpinner size={24} label="Loading steps..." />
                </div>
              ) : !steps || steps.length === 0 ? (
                <p
                  style={{
                    fontSize: "0.82rem",
                    color: "var(--text-muted)",
                    padding: "8px 0",
                  }}
                >
                  No steps recorded for this job
                </p>
              ) : (
                <table style={{ width: "100%", borderCollapse: "collapse" }}>
                  <thead>
                    <tr>
                      {["#", "Name", "Phase", "Status", "Duration"].map((header) => (
                        <th
                          key={header}
                          style={{
                            padding: "6px 12px",
                            textAlign: "left",
                            fontSize: "0.7rem",
                            fontWeight: 600,
                            textTransform: "uppercase",
                            letterSpacing: "0.05em",
                            color: "var(--muted)",
                            fontFamily: "var(--mono)",
                            borderBottom: "1px solid var(--border)",
                            whiteSpace: "nowrap",
                          }}
                        >
                          {header}
                        </th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {steps
                      .sort((a, b) => a.ordinal - b.ordinal)
                      .map((step) => (
                        <StepRow key={step.id} step={step} />
                      ))}
                  </tbody>
                </table>
              )}

              {/* Job error message if failed */}
              {job.error && (
                <div
                  style={{
                    marginTop: 12,
                    padding: "8px 12px",
                    borderRadius: 6,
                    fontSize: "0.78rem",
                    fontFamily: "var(--mono)",
                    color: "var(--danger)",
                    background: "color-mix(in srgb, var(--danger) 8%, transparent)",
                    border: "1px solid color-mix(in srgb, var(--danger) 20%, transparent)",
                    wordBreak: "break-all",
                  }}
                >
                  {job.error}
                </div>
              )}
            </div>
          </td>
        </tr>
      )}
    </>
  );
}

// ─── Step Row Component ───────────────────────────────────────────────

function StepRow({ step }: { step: JobStep }): ReactElement {
  const [hovered, setHovered] = useState(false);

  return (
    <tr
      onMouseEnter={() => {
        setHovered(true);
      }}
      onMouseLeave={() => {
        setHovered(false);
      }}
      style={{
        background: hovered ? "color-mix(in srgb, var(--surface) 50%, transparent)" : "transparent",
        borderBottom: "1px solid color-mix(in srgb, var(--border) 50%, transparent)",
        transition: "background 100ms ease",
      }}
    >
      <td
        style={{
          padding: "6px 12px",
          fontSize: "0.78rem",
          fontFamily: "var(--mono)",
          color: "var(--muted)",
        }}
      >
        {String(step.ordinal)}
      </td>
      <td
        style={{
          padding: "6px 12px",
          fontSize: "0.8rem",
          color: "var(--text)",
        }}
      >
        {step.name}
      </td>
      <td
        style={{
          padding: "6px 12px",
          fontSize: "0.75rem",
          fontFamily: "var(--mono)",
          color: "var(--text-muted)",
          textTransform: "lowercase",
        }}
      >
        {step.phase}
      </td>
      <td style={{ padding: "6px 12px" }}>
        <StatusBadge status={step.status} />
      </td>
      <td
        style={{
          padding: "6px 12px",
          fontSize: "0.78rem",
          fontFamily: "var(--mono)",
          color: "var(--text-muted)",
          whiteSpace: "nowrap",
        }}
      >
        {formatStepDuration(step.durationMs)}
      </td>
    </tr>
  );
}
