import { useQuery } from '@tanstack/react-query';
import { useCallback, useEffect, useMemo, useState } from 'react';
import {
  Activity,
  Terminal,
  CheckCircle,
  AlertCircle,
  ChevronDown,
  ChevronRight,
  Copy,
  Filter,
  X,
  RefreshCw,
} from 'lucide-react';
import {
  jobsService,
  JobHistoryEntry,
  JobStatus,
  JOB_LABELS,
  getJobDataSummary,
  getJobDataDetails,
  getJobStatus,
} from '../services/jobsService';
import { formatDistanceToNow, format } from 'date-fns';

/* ─────────────────────────────────────────── Filter state ─────────────────────────────────────────── */

interface Filters {
  status: JobStatus | 'all';
  type: string;
}

const INITIAL_FILTERS: Filters = { status: 'all', type: 'all' };

/* ─────────────────────────────────────────── Helpers ─────────────────────────────────────────────── */

const JOB_TYPES = Object.keys(JOB_LABELS);

function statusBgColor(status: JobStatus): string {
  switch (status) {
    case 'running':
      return 'bg-accent/10 border-accent/25';
    case 'failed':
      return 'bg-red-400/10 border-red-400/25';
    case 'completed':
      return 'bg-green-400/10 border-green-400/25';
  }
}

function formatDuration(ms: number): string {
  const seconds = Math.floor(ms / 1000);
  if (seconds < 60) return `${seconds}s`;
  const minutes = Math.floor(seconds / 60);
  const remainSec = seconds % 60;
  return `${minutes}m ${remainSec}s`;
}

/* ─────────────────────────────────────────── Sub-components ──────────────────────────────────────── */

/**
 * One queue counter. Every tile used to carry its own hue and a giant ghost icon,
 * which made a queue at rest look like an alarm panel. Now the number is mono and
 * neutral; colour appears only when the value is one that wants attention.
 */
function StatCard({
  label,
  value,
  tone = 'neutral',
}: {
  label: string;
  value: number;
  tone?: 'neutral' | 'active' | 'bad';
}) {
  const live = value > 0;
  const valueColor = !live
    ? 'text-disabled'
    : tone === 'bad'
      ? 'text-red'
      : tone === 'active'
        ? 'text-accent'
        : 'text-text';
  return (
    <div className="rounded-lg border border-border bg-surface0/50 px-3 py-2.5">
      <p className="text-[10px] font-semibold uppercase tracking-[0.1em] text-muted">{label}</p>
      <p className={`mt-1 font-mono text-2xl tabular-nums ${valueColor}`}>{value.toLocaleString()}</p>
    </div>
  );
}

function StatusBadge({ status }: { status: JobStatus }) {
  const dotColor = status === 'running' ? 'bg-accent' : status === 'failed' ? 'bg-red-400' : 'bg-green-400';
  const label = status === 'running' ? 'Running' : status === 'failed' ? 'Failed' : 'Completed';

  return (
    <span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-medium ${statusBgColor(status)}`}>
      <span className={`w-1.5 h-1.5 rounded-full ${dotColor} ${status === 'running' ? 'animate-pulse' : ''}`} />
      {label}
    </span>
  );
}

function ExpandedDetail({ label, value }: { label: string; value: string }) {
  return (
    <div className="flex items-start gap-2 text-xs">
      <span className="text-muted shrink-0 w-28">{label}</span>
      <span className="text-text font-mono break-all">{value || '—'}</span>
    </div>
  );
}

/* ─────────────────────────────────────────── Job row ─────────────────────────────────────────────── */

function JobRow({
  job,
  isExpanded,
  onToggle,
}: {
  job: JobHistoryEntry;
  isExpanded: boolean;
  onToggle: () => void;
}) {
  const status = getJobStatus(job);
  const summary = getJobDataSummary(job.name, job.data);
  const details = useMemo(() => getJobDataDetails(job.name, job.data), [job.name, job.data]);
  const duration = job.finishedOn && job.timestamp ? job.finishedOn - job.timestamp : null;
  const hasReturnValue = job.returnvalue !== undefined && job.returnvalue !== null;

  return (
    <div
      className={`bg-surface0 border border-border rounded-lg transition-colors ${
        isExpanded ? 'border-accent/40' : 'hover:border-accent/30'
      }`}
    >
      {/* ── collapsed row ── */}
      <button
        onClick={onToggle}
        className="w-full flex items-center gap-3 px-4 py-3 text-left"
      >
        {/* status icon */}
        <div className="shrink-0">
          {status === 'running' && <Activity className="w-4 h-4 text-accent animate-spin" />}
          {status === 'failed' && <AlertCircle className="w-4 h-4 text-red-400" />}
          {status === 'completed' && <CheckCircle className="w-4 h-4 text-green-400" />}
        </div>

        {/* job name + summary */}
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            <span className="font-medium text-sm">{JOB_LABELS[job.name] || job.name}</span>
            <StatusBadge status={status} />
          </div>
          {summary && (
            <p className="text-xs text-muted mt-0.5 truncate max-w-md">{summary}</p>
          )}
        </div>

        {/* timestamp + duration */}
        <div className="hidden sm:flex flex-col items-end text-xs text-muted shrink-0">
          <span>{formatDistanceToNow(new Date(job.timestamp), { addSuffix: true })}</span>
          {duration !== null && (
            <span className="opacity-60">{formatDuration(duration)}</span>
          )}
        </div>

        {/* expand icon */}
        <div className="shrink-0 text-muted">
          {isExpanded ? <ChevronDown className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />}
        </div>
      </button>

      {/* ── expanded detail ── */}
      {isExpanded && (
        <div className="border-t border-border px-4 py-3 space-y-3">
          {/* Job metadata */}
          <div className="space-y-1">
            <ExpandedDetail label="Job ID" value={job.id} />
            <ExpandedDetail label="Created" value={format(new Date(job.timestamp), 'PPpp')} />
            {job.finishedOn && (
              <ExpandedDetail label="Finished" value={format(new Date(job.finishedOn), 'PPpp')} />
            )}
            {duration !== null && (
              <ExpandedDetail label="Duration" value={formatDuration(duration)} />
            )}
          </div>

          {/* Job-specific payload */}
          {details.length > 0 && (
            <div>
              <p className="text-xs font-medium text-muted mb-1 uppercase tracking-wider">Payload</p>
              <div className="space-y-1">
                {details.map((d) => (
                  <ExpandedDetail key={d.label} label={d.label} value={d.value} />
                ))}
              </div>
            </div>
          )}

          {/* Raw data (collapsible) */}
          {Object.keys(job.data).length > 0 && (
            <RawDataBlock label="Raw Payload" data={job.data} />
          )}

          {/* Return value */}
          {hasReturnValue && <RawDataBlock label="Return Value" data={job.returnvalue} />}

          {/* Failed reason */}
          {job.failedReason && (
            <div>
              <p className="text-xs font-medium text-red-400 mb-1 uppercase tracking-wider">Error</p>
              <div className="bg-red-400/5 border border-red-400/20 rounded p-2">
                <pre className="text-xs text-red-300 whitespace-pre-wrap font-mono">{job.failedReason}</pre>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

/* ── Raw JSON expandable block ── */

function RawDataBlock({ label, data }: { label: string; data: unknown }) {
  const [open, setOpen] = useState(false);
  const text = JSON.stringify(data, null, 2);

  return (
    <div>
      <button
        onClick={() => setOpen((p) => !p)}
        className="flex items-center gap-1 text-xs font-medium text-muted uppercase tracking-wider hover:text-text transition-colors"
      >
        {open ? <ChevronDown className="w-3 h-3" /> : <ChevronRight className="w-3 h-3" />}
        {label}
      </button>
      {open && (
        <div className="relative mt-1">
          <pre className="text-xs text-muted bg-bg1/50 border border-border/70 rounded p-2 overflow-x-auto max-h-48 font-mono">
            {text}
          </pre>
          <button
            onClick={() => navigator.clipboard.writeText(text)}
            className="absolute top-1 right-1 p-1 rounded text-muted hover:text-text hover:bg-surface0 transition-colors"
            title="Copy to clipboard"
          >
            <Copy className="w-3.5 h-3.5" />
          </button>
        </div>
      )}
    </div>
  );
}

/* ─────────────────────────────────────────── Filter bar ──────────────────────────────────────────── */

function FilterBar({
  filters,
  onChange,
  totalCount,
  filteredCount,
}: {
  filters: Filters;
  onChange: (f: Filters) => void;
  totalCount: number;
  filteredCount: number;
}) {
  const setStatus = (status: Filters['status']) => onChange({ ...filters, status });
  const setType = (type: string) => onChange({ ...filters, type });

  const hasActiveFilters = filters.status !== 'all' || filters.type !== 'all';
  const statusOptions: { value: Filters['status']; label: string }[] = [
    { value: 'all', label: 'All' },
    { value: 'completed', label: 'Completed' },
    { value: 'failed', label: 'Failed' },
    { value: 'running', label: 'Running' },
  ];
  const typeOptions = JOB_TYPES;

  return (
    <div className="flex items-center gap-3 flex-wrap">
      {/* Status pills */}
      <div className="flex items-center gap-1 bg-surface0 border border-border rounded-lg p-0.5">
        {statusOptions.map((opt) => (
          <button
            key={opt.value}
            onClick={() => setStatus(opt.value)}
            className={`px-2.5 py-1 text-xs font-medium rounded-md transition-colors ${
              filters.status === opt.value
                ? 'bg-accent/15 text-accent'
                : 'text-muted hover:text-text'
            }`}
          >
            {opt.label}
          </button>
        ))}
      </div>

      {/* Type dropdown */}
      <div className="relative">
        <select
          value={filters.type}
          onChange={(e) => setType(e.target.value)}
          className="appearance-none bg-surface0 border border-border rounded-lg px-3 py-1.5 pr-8 text-xs font-medium text-text cursor-pointer focus:outline-none focus:border-accent/50"
        >
          <option value="all">All Types</option>
          {typeOptions.map((t) => (
            <option key={t} value={t}>{JOB_LABELS[t] || t}</option>
          ))}
        </select>
        <Filter className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted" />
      </div>

      {/* Result count */}
      <span className="text-xs text-muted">
        {filteredCount} / {totalCount} jobs
      </span>

      {/* Clear filters */}
      {hasActiveFilters && (
        <button
          onClick={() => onChange(INITIAL_FILTERS)}
          className="flex items-center gap-1 text-xs text-muted hover:text-text transition-colors"
        >
          <X className="w-3 h-3" />
          Clear
        </button>
      )}
    </div>
  );
}

/** Human-readable one-liner for a failed admin request. */
function describeError(err: unknown): string {
  const status = (err as { response?: { status?: number } })?.response?.status;
  if (status === 401 || status === 403) {
    return `Request rejected (HTTP ${status}) — the admin API key is missing or wrong.`;
  }
  if (status) return `Request failed with HTTP ${status}.`;
  const message = err instanceof Error ? err.message : String(err);
  return message || 'Unknown error.';
}

/* ─────────────────────────────────────────── Page ────────────────────────────────────────────────── */

export default function JobsPage() {
  const [autoRefresh, setAutoRefresh] = useState(true);
  const [selectedTab, setSelectedTab] = useState<'overview' | 'history'>('overview');
  const [filters, setFilters] = useState<Filters>(INITIAL_FILTERS);
  const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());

  const statsQ = useQuery({
    queryKey: ['queueStats'],
    queryFn: () => jobsService.getQueueStats(),
    // Stop polling once the endpoint is failing — otherwise a permission or
    // outage error is retried silently every 3s forever.
    refetchInterval: (query) => (autoRefresh && !query.state.error ? 3000 : false),
    staleTime: 1000,
  });

  const historyQ = useQuery({
    queryKey: ['jobHistory'],
    queryFn: () => jobsService.getJobHistory(200),
    refetchInterval: (query) => (autoRefresh && !query.state.error ? 5000 : false),
    staleTime: 2000,
  });

  const { data: stats, refetch: refetchStats } = statsQ;
  const { data: history, refetch: refetchHistory } = historyQ;
  const loadError = statsQ.error ?? historyQ.error;

  useEffect(() => {
    if (selectedTab === 'overview') refetchStats();
    else refetchHistory();
  }, [selectedTab, refetchStats, refetchHistory]);

  const toggleExpanded = useCallback((id: string) => {
    setExpandedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);

  // Filtered & sorted history
  const filteredHistory = useMemo(() => {
    if (!history) return [];
    return history
      .filter((job) => {
        if (filters.status !== 'all' && getJobStatus(job) !== filters.status) return false;
        if (filters.type !== 'all' && job.name !== filters.type) return false;
        return true;
      });
  }, [history, filters]);

  return (
    <div className="flex-1 flex flex-col overflow-hidden">
      {/* ── Header ── */}
      <div className="flex flex-wrap items-end justify-between gap-3 border-b border-border p-4">
        <div>
          <h1 className="text-2xl font-semibold tracking-tight text-text sm:text-3xl">Jobs</h1>
          <p className="mt-1 font-mono text-xs tabular-nums text-machine">
            {stats
              ? `${stats.waiting + stats.active + stats.delayed} queued · ${stats.failed} failed`
              : 'reading queue…'}
            {autoRefresh ? ' · refresh 5s' : ' · refresh off'}
          </p>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={() => { refetchStats(); refetchHistory(); }}
            className="flex items-center gap-1.5 rounded-lg border border-border px-3 py-2 text-xs text-secondary transition-colors hover:border-accent/40 hover:text-text"
            title="Refresh now"
          >
            <RefreshCw className="w-3.5 h-3.5" />
            Refresh
          </button>
          <button
            type="button"
            onClick={() => setAutoRefresh(!autoRefresh)}
            aria-pressed={autoRefresh}
            className={`flex items-center gap-2 rounded-lg border px-3 py-2 text-xs transition-colors ${
              autoRefresh
                ? 'border-accent/50 bg-accent/10 text-accent'
                : 'border-border text-secondary hover:text-text'
            }`}
          >
            <span className={`h-1.5 w-1.5 rounded-full ${autoRefresh ? 'bg-accent' : 'bg-disabled'}`} />
            Auto-refresh
          </button>
        </div>
      </div>

      {/* ── Tabs ── */}
      <div className="flex border-b border-border px-4">
        <button
          onClick={() => setSelectedTab('overview')}
          className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
            selectedTab === 'overview' ? 'border-accent text-text' : 'border-transparent text-muted hover:text-text'
          }`}
        >
          Overview
        </button>
        <button
          onClick={() => setSelectedTab('history')}
          className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
            selectedTab === 'history' ? 'border-accent text-text' : 'border-transparent text-muted hover:text-text'
          }`}
        >
          History
        </button>
      </div>

      {/* ── Content ── */}
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {/* ── Error banner ── */}
        {loadError && (
          <div className="flex items-start gap-2 rounded-md border border-red-500/40 bg-red-500/10 px-3 py-2 text-sm text-red-300">
            <AlertCircle className="w-4 h-4 mt-0.5 shrink-0" />
            <div className="space-y-1">
              <p className="font-medium">Could not load job data</p>
              <p className="text-xs opacity-80">{describeError(loadError)}</p>
              <button
                onClick={() => { refetchStats(); refetchHistory(); }}
                className="text-xs underline hover:no-underline"
              >
                Retry
              </button>
            </div>
          </div>
        )}

        {/* ── Overview tab ── */}
        {selectedTab === 'overview' && !stats && !loadError && (
          <div className="grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-6">
            {Array.from({ length: 6 }).map((_, i) => (
              <div key={i} className="skeleton h-[70px] rounded-lg" />
            ))}
          </div>
        )}
        {selectedTab === 'overview' && stats && (
          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
            <StatCard label="Waiting" value={stats.waiting} />
            <StatCard label="Active" value={stats.active} tone="active" />
            <StatCard label="Completed" value={stats.completed} />
            <StatCard label="Failed" value={stats.failed} tone="bad" />
            <StatCard label="Delayed" value={stats.delayed} />
            <StatCard label="Paused" value={stats.paused} />
          </div>
        )}

        {/* ── History tab ── */}
        {selectedTab === 'history' && (
          <>
            {/* Filter bar */}
            {history && history.length > 0 && (
              <FilterBar
                filters={filters}
                onChange={setFilters}
                totalCount={history.length}
                filteredCount={filteredHistory.length}
              />
            )}

            {/* Job list */}
            {filteredHistory.length === 0 ? (
              <div className="text-center py-16 text-muted">
                <Terminal className="w-12 h-12 mx-auto mb-4 opacity-30" />
                <p className="text-sm font-medium">
                  {history && history.length > 0
                    ? 'No jobs match the current filters'
                    : 'No job history yet'}
                </p>
                {(history && history.length > 0) && (
                  <button
                    onClick={() => setFilters(INITIAL_FILTERS)}
                    className="mt-2 text-xs text-accent hover:underline"
                  >
                    Clear filters
                  </button>
                )}
              </div>
            ) : (
              <div className="space-y-2">
                {filteredHistory.map((job) => (
                  <JobRow
                    key={job.id}
                    job={job}
                    isExpanded={expandedIds.has(job.id)}
                    onToggle={() => toggleExpanded(job.id)}
                  />
                ))}
              </div>
            )}
          </>
        )}
      </div>
    </div>
  );
}