// =============================================================================
// HeadlineSift.com — Job List Table
// =============================================================================
"use client";

import { useRouter, useSearchParams } from "next/navigation";
import { useCallback, useTransition, useState } from "react";
import { retryJob, cancelJob } from "./actions";
import { cn } from "@/lib/utils";

// ============================================================================
// Types
// ============================================================================

export interface JobRow {
  id: string;
  type: string;
  status: string;
  payloadJson: string | null;
  attempts: number;
  maxAttempts: number;
  runAfter: Date;
  lockedAt: Date | null;
  lockedBy: string | null;
  startedAt: Date | null;
  completedAt: Date | null;
  errorMessage: string | null;
  createdAt: Date;
  updatedAt: Date;
}

interface JobTableProps {
  jobs: JobRow[];
  statusFilter: string | null;
  typeFilter: string | null;
  page: number;
  totalPages: number;
  totalCount: number;
}

// ============================================================================
// Constants
// ============================================================================

const JOB_TYPE_LABELS: Record<string, string> = {
  FETCH_SOURCE: "Fetch Source",
  FETCH_ALL_SOURCES: "Fetch All Sources",
  CLUSTER_ARTICLES: "Cluster Articles",
  RANK_STORIES: "Rank Stories",
  GENERATE_AI_ANALYSIS: "AI Analysis",
  PUBLISH_APPROVED_STORIES: "Publish Stories",
  BACKUP_DATABASE: "Backup DB",
};

const JOB_TYPE_ICONS: Record<string, string> = {
  FETCH_SOURCE: "📥",
  FETCH_ALL_SOURCES: "📡",
  CLUSTER_ARTICLES: "🔗",
  RANK_STORIES: "📈",
  GENERATE_AI_ANALYSIS: "🤖",
  PUBLISH_APPROVED_STORIES: "📰",
  BACKUP_DATABASE: "💾",
};

// ============================================================================
// Sub-components
// ============================================================================

function StatusBadge({ status }: { status: string }) {
  const colors: Record<string, string> = {
    PENDING: "bg-slate-100 text-slate-700",
    RUNNING: "bg-blue-50 text-blue-700",
    COMPLETED: "bg-green-50 text-green-700",
    FAILED: "bg-red-50 text-red-700",
    CANCELLED: "bg-amber-50 text-amber-700",
  };

  return (
    <span
      className={cn(
        "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-2xs font-semibold uppercase tracking-wider",
        colors[status] ?? "bg-slate-100 text-slate-600",
      )}
    >
      {status === "RUNNING" && (
        <span className="inline-block h-1.5 w-1.5 rounded-full bg-blue-500 animate-pulse" />
      )}
      {status}
    </span>
  );
}

function TypeBadge({ type }: { type: string }) {
  return (
    <span className="inline-flex items-center gap-1 text-sm font-medium text-heading">
      <span aria-hidden="true">{JOB_TYPE_ICONS[type] ?? "⚙️"}</span>
      {JOB_TYPE_LABELS[type] ?? type}
    </span>
  );
}

function AttemptsBadge({
  attempts,
  maxAttempts,
  status,
}: {
  attempts: number;
  maxAttempts: number;
  status: string;
}) {
  if (status === "FAILED") {
    return (
      <span className="text-2xs font-semibold text-red-600 tabular-nums">
        {attempts}/{maxAttempts}
      </span>
    );
  }
  if (attempts > 0) {
    return (
      <span className="text-2xs text-body-muted tabular-nums">
        {attempts}/{maxAttempts}
      </span>
    );
  }
  return (
    <span className="text-2xs text-body-muted/50 tabular-nums">
      0/{maxAttempts}
    </span>
  );
}

function RelativeTime({ date }: { date: Date | null }) {
  if (!date) return <span className="text-body-muted/50">—</span>;

  const now = Date.now();
  const diffMs = now - date.getTime();
  const diffSec = Math.floor(diffMs / 1000);
  const diffMin = Math.floor(diffSec / 60);
  const diffHr = Math.floor(diffMin / 60);
  const diffDay = Math.floor(diffHr / 24);

  let text: string;
  if (diffSec < 60) text = "just now";
  else if (diffMin < 60) text = `${diffMin}m ago`;
  else if (diffHr < 24) text = `${diffHr}h ago`;
  else if (diffDay < 7) text = `${diffDay}d ago`;
  else text = date.toLocaleDateString();

  return (
    <span
      className="text-2xs text-body-muted"
      title={date.toISOString()}
    >
      {text}
    </span>
  );
}

function Duration({
  startedAt,
  completedAt,
}: {
  startedAt: Date | null;
  completedAt: Date | null;
}) {
  if (!startedAt || !completedAt) {
    return <span className="text-body-muted/50">—</span>;
  }

  const ms = completedAt.getTime() - startedAt.getTime();
  if (ms < 1000) return <span className="text-2xs text-body-muted">{ms}ms</span>;
  if (ms < 60_000) return <span className="text-2xs text-body-muted">{(ms / 1000).toFixed(1)}s</span>;
  const min = Math.floor(ms / 60_000);
  const sec = Math.floor((ms % 60_000) / 1000);
  return <span className="text-2xs text-body-muted">{min}m {sec}s</span>;
}

function EmptyState({ hasFilters }: { hasFilters: boolean }) {
  return (
    <div className="flex flex-col items-center justify-center py-16 text-center">
      <span className="text-5xl" aria-hidden="true">
        {hasFilters ? "🔍" : "⚙️"}
      </span>
      <h3 className="mt-4 text-lg font-semibold text-heading">
        {hasFilters ? "No jobs match your filters" : "No jobs yet"}
      </h3>
      <p className="mt-2 max-w-md text-sm text-body-muted">
        {hasFilters
          ? "Try adjusting your filter selection."
          : "Jobs are created automatically by the scheduler when background work is needed. Run the worker with \"npm run process:jobs\" to start processing."}
      </p>
    </div>
  );
}

// ============================================================================
// Table Component
// ============================================================================

export default function JobTable({
  jobs,
  statusFilter,
  typeFilter,
  page,
  totalPages,
  totalCount,
}: JobTableProps) {
  const router = useRouter();
  const searchParams = useSearchParams();
  const [isPending, startTransition] = useTransition();
  const [expandedJobId, setExpandedJobId] = useState<string | null>(null);

  const navigate = useCallback(
    (overrides: Record<string, string | null>) => {
      const params = new URLSearchParams(searchParams.toString());
      for (const [key, value] of Object.entries(overrides)) {
        if (value === null) {
          params.delete(key);
        } else {
          params.set(key, value);
        }
      }
      startTransition(() => {
        router.push(`/admin/jobs?${params.toString()}`);
      });
    },
    [router, searchParams, startTransition],
  );

  const handleRetry = useCallback(
    (id: string) => {
      if (!window.confirm("Retry this job? It will be reset to PENDING.")) return;
      startTransition(() => {
        retryJob(id);
      });
    },
    [startTransition],
  );

  const handleCancel = useCallback(
    (id: string) => {
      if (!window.confirm("Cancel this job?")) return;
      startTransition(() => {
        cancelJob(id);
      });
    },
    [startTransition],
  );

  const toggleExpand = useCallback((id: string) => {
    setExpandedJobId((prev) => (prev === id ? null : id));
  }, []);

  const hasFilters = statusFilter !== null || typeFilter !== null;

  return (
    <div className="space-y-4">
      {/* ── Filter Toolbar ── */}
      <div className="flex flex-wrap items-center gap-3">
        {/* Status Filter */}
        <select
          value={statusFilter ?? ""}
          onChange={(e) =>
            navigate({ status: e.target.value || null, page: null })
          }
          className="input text-xs"
          style={{ maxWidth: "9rem" }}
        >
          <option value="">All statuses</option>
          <option value="PENDING">Pending</option>
          <option value="RUNNING">Running</option>
          <option value="COMPLETED">Completed</option>
          <option value="FAILED">Failed</option>
          <option value="CANCELLED">Cancelled</option>
        </select>

        {/* Type Filter */}
        <select
          value={typeFilter ?? ""}
          onChange={(e) =>
            navigate({ type: e.target.value || null, page: null })
          }
          className="input text-xs"
          style={{ maxWidth: "11rem" }}
        >
          <option value="">All types</option>
          <option value="FETCH_SOURCE">Fetch Source</option>
          <option value="FETCH_ALL_SOURCES">Fetch All Sources</option>
          <option value="CLUSTER_ARTICLES">Cluster Articles</option>
          <option value="RANK_STORIES">Rank Stories</option>
          <option value="GENERATE_AI_ANALYSIS">AI Analysis</option>
          <option value="PUBLISH_APPROVED_STORIES">Publish Stories</option>
          <option value="BACKUP_DATABASE">Backup DB</option>
        </select>

        {/* Result count */}
        {hasFilters && (
          <span className="text-2xs text-body-muted">
            {totalCount} result{totalCount !== 1 ? "s" : ""}
          </span>
        )}
      </div>

      {/* ── Table or Empty State ── */}
      {jobs.length === 0 ? (
        <div className="card">
          <EmptyState hasFilters={hasFilters} />
        </div>
      ) : (
        <div className="card overflow-x-auto p-0">
          <table className="w-full text-sm">
            <thead>
              <tr className="border-b border-border bg-surface-secondary text-left">
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted">
                  Job
                </th>
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted">
                  Status
                </th>
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted hidden sm:table-cell w-16">
                  Tries
                </th>
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted hidden md:table-cell">
                  Created
                </th>
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted hidden lg:table-cell">
                  Duration
                </th>
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted hidden xl:table-cell max-w-[200px]">
                  Error
                </th>
                <th className="px-4 py-3 text-xs font-semibold uppercase tracking-wide text-body-muted w-28">
                  <span className="sr-only">Actions</span>
                </th>
              </tr>
            </thead>
            <tbody className="divide-y divide-border">
              {jobs.map((job) => {
                const isExpanded = expandedJobId === job.id;
                return (
                  <tr key={job.id}>
                    <td className="px-4 py-3">
                      <button
                        type="button"
                        onClick={() => toggleExpand(job.id)}
                        className="text-left hover:underline decoration-dotted"
                      >
                        <TypeBadge type={job.type} />
                      </button>
                      {isExpanded && job.payloadJson && (
                        <pre className="mt-2 max-h-32 overflow-auto rounded bg-surface-tertiary p-2 text-xs text-body-muted whitespace-pre-wrap break-all">
                          {(() => {
                            try {
                              return JSON.stringify(
                                JSON.parse(job.payloadJson),
                                null,
                                2,
                              );
                            } catch {
                              return job.payloadJson;
                            }
                          })()}
                        </pre>
                      )}
                    </td>

                    {/* Status */}
                    <td className="px-4 py-3">
                      <StatusBadge status={job.status} />
                    </td>

                    {/* Attempts */}
                    <td className="px-4 py-3 hidden sm:table-cell">
                      <AttemptsBadge
                        attempts={job.attempts}
                        maxAttempts={job.maxAttempts}
                        status={job.status}
                      />
                    </td>

                    {/* Created */}
                    <td className="px-4 py-3 hidden md:table-cell">
                      <RelativeTime date={job.createdAt} />
                    </td>

                    {/* Duration */}
                    <td className="px-4 py-3 hidden lg:table-cell">
                      <Duration
                        startedAt={job.startedAt}
                        completedAt={job.completedAt}
                      />
                    </td>

                    {/* Error Message */}
                    <td className="px-4 py-3 hidden xl:table-cell max-w-[200px]">
                      {job.errorMessage ? (
                        <span
                          className="block truncate text-2xs text-red-600"
                          title={job.errorMessage}
                        >
                          {job.errorMessage}
                        </span>
                      ) : (
                        <span className="text-body-muted/50">—</span>
                      )}
                    </td>

                    {/* Actions */}
                    <td className="px-4 py-3">
                      <div className="flex items-center gap-1">
                        {/* Retry — only for FAILED */}
                        {job.status === "FAILED" && (
                          <button
                            type="button"
                            onClick={() => handleRetry(job.id)}
                            disabled={isPending}
                            className="rounded px-2 py-1 text-2xs font-medium text-brand-600 hover:bg-brand-50 transition-colors"
                          >
                            Retry
                          </button>
                        )}

                        {/* Cancel — only for PENDING */}
                        {job.status === "PENDING" && (
                          <button
                            type="button"
                            onClick={() => handleCancel(job.id)}
                            disabled={isPending}
                            className="rounded px-2 py-1 text-2xs font-medium text-amber-600 hover:bg-amber-50 transition-colors"
                          >
                            Cancel
                          </button>
                        )}
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>

          {/* Footer: count + pagination */}
          <div className="flex items-center justify-between border-t border-border px-4 py-3">
            <span className="text-xs text-body-muted">
              {totalCount} {totalCount === 1 ? "job" : "jobs"}
            </span>

            {totalPages > 1 && (
              <div className="flex items-center gap-2">
                <button
                  type="button"
                  disabled={page <= 1}
                  onClick={() =>
                    navigate({ page: String(page - 1) })
                  }
                  className="rounded px-2 py-1 text-xs text-brand-600 hover:bg-brand-50 disabled:text-body-muted/30 disabled:cursor-not-allowed transition-colors"
                >
                  Previous
                </button>
                <span className="text-xs text-body-muted">
                  {page} / {totalPages}
                </span>
                <button
                  type="button"
                  disabled={page >= totalPages}
                  onClick={() =>
                    navigate({ page: String(page + 1) })
                  }
                  className="rounded px-2 py-1 text-xs text-brand-600 hover:bg-brand-50 disabled:text-body-muted/30 disabled:cursor-not-allowed transition-colors"
                >
                  Next
                </button>
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}
