import { useState } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import {
  Activity, CheckCircle2, XCircle, Loader2, Clock, RefreshCw,
  ChevronDown, ChevronRight, RotateCcw, Terminal, Cpu, Image,
  Trash2, Ban, ListOrdered, FileCode2,
} from 'lucide-react'
import { Link } from 'react-router-dom'
import {
  getWorkerActivity, reprocessCadFile, CadActivityEntry, RenderLog, RenderJobEntry,
  getQueueStatus, purgeQueue, cancelTask, QueueTask,
} from '../api/worker'
import LiveRenderLog from '../components/LiveRenderLog'

type UnifiedEvent =
  | { kind: 'cad';    ts: number; entry: CadActivityEntry }
  | { kind: 'render'; ts: number; job: RenderJobEntry }

export default function WorkerActivityPage() {
  const qc = useQueryClient()
  const [expanded, setExpanded] = useState<Set<string>>(new Set())

  const { data, isLoading, dataUpdatedAt } = useQuery({
    queryKey: ['worker-activity'],
    queryFn: getWorkerActivity,
  })

  const reprocessMut = useMutation({
    mutationFn: reprocessCadFile,
    onSuccess: () => {
      toast.success('Re-queued for full reprocessing')
      qc.invalidateQueries({ queryKey: ['worker-activity'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const lastUpdated = dataUpdatedAt
    ? new Date(dataUpdatedAt).toLocaleTimeString('de-DE')
    : '—'

  const toggle = (id: string) =>
    setExpanded((s) => {
      const n = new Set(s)
      n.has(id) ? n.delete(id) : n.add(id)
      return n
    })

  // Merge + sort both event streams into one unified timeline
  const events: UnifiedEvent[] = []
  if (data) {
    for (const entry of data.cad_processing) {
      events.push({ kind: 'cad', ts: new Date(entry.updated_at).getTime(), entry })
    }
    for (const job of data.render_jobs) {
      events.push({ kind: 'render', ts: new Date(job.updated_at).getTime(), job })
    }
    events.sort((a, b) => b.ts - a.ts)
  }

  const isEmpty = !isLoading && events.length === 0

  return (
    <div className="p-8 space-y-6">
      <div className="flex items-center gap-3">
        <Activity size={22} className="text-accent" />
        <h1 className="text-2xl font-bold text-content">Worker Activity</h1>
        <span className="ml-auto flex items-center gap-2 text-xs text-content-muted">
          Auto-refresh every 5 s · Last: {lastUpdated}
          <button
            onClick={() => qc.invalidateQueries({ queryKey: ['worker-activity'] })}
            className="p-1 rounded hover:bg-surface-muted"
            title="Refresh now"
          >
            <RefreshCw size={13} />
          </button>
        </span>
      </div>

      {/* Queue panel */}
      <QueuePanel />

      {/* Summary */}
      {data && (
        <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
          <StatCard label="CAD active" value={data.active_count}
            color={data.active_count > 0 ? 'text-status-info-text' : 'text-content-secondary'} />
          <StatCard label="CAD failed" value={data.failed_count}
            color={data.failed_count > 0 ? 'text-red-600' : 'text-content-secondary'} />
          <StatCard label="Rendering" value={data.render_active_count}
            color={data.render_active_count > 0 ? 'text-status-info-text' : 'text-content-secondary'} />
          <StatCard label="Render failed" value={data.render_failed_count}
            color={data.render_failed_count > 0 ? 'text-red-600' : 'text-content-secondary'} />
        </div>
      )}

      {isLoading && (
        <div className="flex items-center gap-2 text-content-muted py-12 justify-center">
          <Loader2 size={18} className="animate-spin" /> Loading activity…
        </div>
      )}

      {isEmpty && (
        <div className="card p-12 text-center text-content-muted">
          <Activity size={32} className="mx-auto mb-3 text-content-muted" />
          <p className="font-medium">No recent activity</p>
          <p className="text-sm mt-1">STEP processing and render jobs will appear here.</p>
        </div>
      )}

      {/* ── Unified timeline ─────────────────────────────────────────────── */}
      {events.length > 0 && (
        <div className="card overflow-hidden divide-y divide-border-light">
          {events.map((ev) =>
            ev.kind === 'render' ? (
              <RenderJobRow key={`render-${ev.job.order_line_id}`} job={ev.job} />
            ) : (
              <CadFileRow
                key={`cad-${ev.entry.cad_file_id}`}
                entry={ev.entry}
                expanded={expanded.has(ev.entry.cad_file_id)}
                onToggle={() => toggle(ev.entry.cad_file_id)}
                onReprocess={() => reprocessMut.mutate(ev.entry.cad_file_id)}
                reprocessPending={reprocessMut.isPending}
              />
            )
          )}
        </div>
      )}
    </div>
  )
}

// ── CAD file row (extracted from inline JSX above) ────────────────────────────

function CadFileRow({
  entry, expanded, onToggle, onReprocess, reprocessPending,
}: {
  entry: CadActivityEntry
  expanded: boolean
  onToggle: () => void
  onReprocess: () => void
  reprocessPending: boolean
}) {
  return (
    <div>
      <div
        className="flex items-center gap-3 px-4 py-3 hover:bg-surface-hover cursor-pointer select-none"
        onClick={onToggle}
      >
        {/* Type badge */}
        <span className="shrink-0 flex items-center gap-1 text-[10px] font-semibold uppercase tracking-wide text-content-muted w-14">
          <FileCode2 size={11} />CAD
        </span>

        {/* Expand toggle */}
        <span className="text-content-muted shrink-0">
          {expanded ? <ChevronDown size={15} /> : <ChevronRight size={15} />}
        </span>

        <StatusIcon status={entry.processing_status} />

        <div className="flex-1 min-w-0">
          <p className="font-mono text-sm text-content truncate" title={entry.original_name}>
            {entry.original_name}
          </p>
          <div className="flex items-center gap-3 mt-0.5 flex-wrap">
            {entry.order_numbers.length > 0 && (
              <div className="flex gap-1 flex-wrap">
                {entry.order_numbers.map((n) => (
                  <span key={n} className="text-xs font-medium bg-surface-muted text-content-secondary px-1.5 py-0.5 rounded">
                    {n}
                  </span>
                ))}
              </div>
            )}
            {entry.file_size != null && (
              <span className="text-xs text-content-muted">{formatBytes(entry.file_size)}</span>
            )}
            {entry.render_log?.renderer && <RendererBadge log={entry.render_log} />}
            {entry.render_log?.total_duration_s != null && (
              <span className="text-xs text-content-muted flex items-center gap-1">
                <Clock size={11} />{entry.render_log.total_duration_s}s
              </span>
            )}
          </div>
          {entry.error_message && (
            <p className="text-xs text-red-500 mt-0.5 truncate" title={entry.error_message}>
              {entry.error_message}
            </p>
          )}
        </div>

        <div className="text-xs text-content-muted shrink-0 text-right hidden sm:block">
          <p>{new Date(entry.updated_at).toLocaleDateString('de-DE')}</p>
          <p>{new Date(entry.updated_at).toLocaleTimeString('de-DE')}</p>
        </div>

        <button
          onClick={(e) => { e.stopPropagation(); onReprocess() }}
          disabled={reprocessPending}
          title="Re-convert STEP + regenerate thumbnail"
          className="shrink-0 p-1.5 rounded text-content-muted hover:text-accent hover:bg-surface-hover transition-colors"
        >
          <RotateCcw size={14} />
        </button>
      </div>

      {expanded && (
        <div className="bg-surface-alt border-t border-border-light px-6 py-4 space-y-4">
          <RenderDetails entry={entry} />
        </div>
      )}
    </div>
  )
}

// ── Queue panel ──────────────────────────────────────────────────────────────

function shortName(taskName: string): string {
  // "app.tasks.step_tasks.regenerate_thumbnail" → "regenerate_thumbnail"
  const parts = taskName.split('.')
  return parts[parts.length - 1] ?? taskName
}

function firstArg(task: QueueTask): string {
  const a = task.args?.[0]
  if (!a) return '—'
  const s = String(a)
  return s.length > 28 ? s.slice(0, 12) + '…' + s.slice(-8) : s
}

function QueuePanel() {
  const qc = useQueryClient()

  const { data: queue, isLoading } = useQuery({
    queryKey: ['worker-queue'],
    queryFn: getQueueStatus,
    refetchInterval: 10_000,
  })

  const purgeMut = useMutation({
    mutationFn: purgeQueue,
    onSuccess: (res) => {
      toast.success(res.message)
      qc.invalidateQueries({ queryKey: ['worker-queue'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Purge failed'),
  })

  const cancelMut = useMutation({
    mutationFn: cancelTask,
    onSuccess: () => {
      toast.success('Task revoked')
      qc.invalidateQueries({ queryKey: ['worker-queue'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Cancel failed'),
  })

  const totalPending = queue?.pending_count ?? 0
  const activeCount  = queue?.active.length ?? 0
  const reservedCount = queue?.reserved.length ?? 0
  const isEmpty = totalPending === 0 && activeCount === 0 && reservedCount === 0

  // Group pending by task name for summary
  const pendingGroups: Record<string, number> = {}
  for (const t of queue?.pending ?? []) {
    const name = shortName(t.task_name)
    pendingGroups[name] = (pendingGroups[name] ?? 0) + 1
  }

  return (
    <div className="card overflow-hidden">
      {/* Header */}
      <div className="flex items-center gap-2 px-4 py-3 border-b border-border-light">
        <ListOrdered size={15} className="text-content-muted" />
        <h2 className="text-sm font-semibold text-content-secondary flex-1">Celery Queue</h2>
        <button
          onClick={() => qc.invalidateQueries({ queryKey: ['worker-queue'] })}
          className="p-1 rounded hover:bg-surface-muted text-content-muted"
          title="Refresh"
        >
          <RefreshCw size={13} className={isLoading ? 'animate-spin' : ''} />
        </button>
        {totalPending > 0 && (
          <button
            onClick={() => {
              if (confirm(`Purge all ${totalPending} pending task(s) from the queue?`)) {
                purgeMut.mutate()
              }
            }}
            disabled={purgeMut.isPending}
            className="flex items-center gap-1 px-2.5 py-1 rounded border border-red-200 text-red-600 text-xs font-medium hover:bg-red-50 transition-colors"
          >
            <Trash2 size={12} />
            Purge all ({totalPending})
          </button>
        )}
      </div>

      {/* Body */}
      <div className="px-4 py-3 space-y-3">
        {/* Summary chips */}
        <div className="flex items-center gap-3 text-xs flex-wrap">
          <span className={`font-semibold ${totalPending > 0 ? 'text-status-warning-text' : 'text-content-muted'}`}>
            {totalPending} pending
          </span>
          <span className="text-content-muted">·</span>
          <span className={`font-semibold ${activeCount > 0 ? 'text-status-info-text' : 'text-content-muted'}`}>
            {activeCount} active
          </span>
          <span className="text-content-muted">·</span>
          <span className="text-content-muted">{reservedCount} reserved</span>
          {queue?.queue_depths && Object.entries(queue.queue_depths).map(([q, n]) => n > 0 && (
            <span key={q} className="ml-1 px-1.5 py-0.5 rounded bg-status-warning-bg border border-border-default text-status-warning-text font-mono">
              {q}: {n}
            </span>
          ))}
        </div>

        {isEmpty && !isLoading && (
          <p className="text-xs text-content-muted py-1">Queue is empty — no pending or active tasks.</p>
        )}

        {/* Active tasks */}
        {(queue?.active.length ?? 0) > 0 && (
          <div>
            <p className="text-[10px] uppercase tracking-wide text-content-muted font-semibold mb-1">Active</p>
            <div className="space-y-1">
              {queue!.active.map((t) => (
                <div key={t.task_id} className="flex items-center gap-2 text-xs rounded-md bg-status-info-bg border border-border-default px-3 py-1.5">
                  <span className="w-2 h-2 rounded-full bg-blue-500 animate-pulse shrink-0" />
                  <span className="font-medium text-status-info-text shrink-0">{shortName(t.task_name)}</span>
                  <span className="text-status-info-text font-mono truncate flex-1">{firstArg(t)}</span>
                  {t.worker && (
                    <span className="text-status-info-text truncate max-w-[120px]">{t.worker.split('@')[0]}</span>
                  )}
                  <button
                    onClick={() => cancelMut.mutate(t.task_id)}
                    disabled={cancelMut.isPending}
                    title="Cancel (revoke + terminate)"
                    className="shrink-0 p-0.5 rounded text-status-info-text hover:text-red-500 hover:bg-red-50 transition-colors"
                  >
                    <Ban size={13} />
                  </button>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Reserved tasks */}
        {(queue?.reserved.length ?? 0) > 0 && (
          <div>
            <p className="text-[10px] uppercase tracking-wide text-content-muted font-semibold mb-1">Reserved (prefetched)</p>
            <div className="space-y-1">
              {queue!.reserved.map((t) => (
                <div key={t.task_id} className="flex items-center gap-2 text-xs rounded-md bg-surface-alt border border-border-default px-3 py-1.5">
                  <span className="w-2 h-2 rounded-full bg-gray-400 shrink-0" />
                  <span className="font-medium text-content-secondary shrink-0">{shortName(t.task_name)}</span>
                  <span className="text-content-secondary font-mono truncate flex-1">{firstArg(t)}</span>
                  <button
                    onClick={() => cancelMut.mutate(t.task_id)}
                    disabled={cancelMut.isPending}
                    title="Cancel (revoke)"
                    className="shrink-0 p-0.5 rounded text-content-muted hover:text-red-500 hover:bg-red-50 transition-colors"
                  >
                    <Ban size={13} />
                  </button>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Pending breakdown (grouped by task name) */}
        {totalPending > 0 && (
          <div>
            <p className="text-[10px] uppercase tracking-wide text-content-muted font-semibold mb-1">
              Pending ({totalPending}{totalPending > 100 ? ', showing first 100' : ''})
            </p>
            <div className="flex flex-wrap gap-1.5">
              {Object.entries(pendingGroups).map(([name, count]) => (
                <span
                  key={name}
                  className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full border border-border-default bg-status-warning-bg text-status-warning-text text-xs font-medium"
                >
                  {name}
                  <span className="bg-status-warning-bg text-status-warning-text rounded-full px-1.5 py-0.5 text-[10px] font-bold leading-none border border-border-default">
                    {count}
                  </span>
                </span>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  )
}


// ── Render job row ───────────────────────────────────────────────────────────

function RenderJobRow({ job }: { job: RenderJobEntry }) {
  const elapsed = job.render_started_at && job.render_completed_at
    ? ((new Date(job.render_completed_at).getTime() - new Date(job.render_started_at).getTime()) / 1000).toFixed(1)
    : null

  return (
    <>
    <div className="flex items-center gap-3 px-4 py-3 hover:bg-surface-hover">
      {/* Type badge */}
      <span className="shrink-0 flex items-center gap-1 text-[10px] font-semibold uppercase tracking-wide text-violet-500 w-14">
        <Image size={11} />Render
      </span>

      <StatusIcon status={job.render_status} />

      <div className="flex-1 min-w-0">
        <div className="flex items-center gap-2 flex-wrap">
          <span className="text-sm font-medium text-content truncate">
            {job.product_name || 'Unknown product'}
          </span>
          {job.output_type_name && (
            <span className="text-xs px-1.5 py-0.5 rounded bg-accent-light text-accent font-medium">
              {job.output_type_name}
            </span>
          )}
        </div>
        <div className="flex items-center gap-3 mt-0.5 flex-wrap">
          {job.order_number && job.order_id ? (
            <Link
              to={`/orders/${job.order_id}`}
              className="text-xs font-medium bg-surface-muted text-content-secondary px-1.5 py-0.5 rounded hover:bg-surface-hover"
            >
              {job.order_number}
            </Link>
          ) : job.order_number ? (
            <span className="text-xs font-medium bg-surface-muted text-content-secondary px-1.5 py-0.5 rounded">
              {job.order_number}
            </span>
          ) : null}
          {job.render_backend_used && (
            <span className="text-xs px-1.5 py-0.5 rounded font-medium bg-status-info-bg text-status-info-text">
              Celery
            </span>
          )}
          {elapsed && (
            <span className="text-xs text-content-muted flex items-center gap-1">
              <Clock size={11} />{elapsed}s
            </span>
          )}
        </div>
      </div>

      <div className="text-xs text-content-muted shrink-0 text-right hidden sm:block">
        <p>{new Date(job.updated_at).toLocaleDateString('de-DE')}</p>
        <p>{new Date(job.updated_at).toLocaleTimeString('de-DE')}</p>
      </div>
    </div>
    <div className="px-4 pb-1">
      <LiveRenderLog
        orderLineId={job.order_line_id}
        isActive={job.render_status === 'processing'}
      />
    </div>
    </>
  )
}

// ── Render detail panel ──────────────────────────────────────────────────────

function RenderDetails({ entry }: { entry: CadActivityEntry }) {
  const log = entry.render_log

  return (
    <div className="space-y-4">
      {/* File info */}
      <Section icon={<Image size={13} />} title="File">
        <KVGrid>
          <KV label="Name" value={entry.original_name} mono />
          <KV label="Size" value={entry.file_size != null ? formatBytes(entry.file_size) : '—'} />
          <KV label="Status" value={entry.processing_status} />
          <KV label="Uploaded" value={new Date(entry.created_at).toLocaleString('de-DE')} />
          <KV label="Last updated" value={new Date(entry.updated_at).toLocaleString('de-DE')} />
          {entry.order_numbers.length > 0 && (
            <KV label="Orders" value={entry.order_numbers.join(', ')} />
          )}
        </KVGrid>
        {entry.error_message && (
          <div className="mt-2 rounded bg-red-50 border border-red-200 px-3 py-2">
            <p className="text-xs font-semibold text-red-600 mb-0.5">Error</p>
            <pre className="text-xs text-red-700 whitespace-pre-wrap break-words">{entry.error_message}</pre>
          </div>
        )}
      </Section>

      {/* Render settings */}
      {log && (
        <Section icon={<Cpu size={13} />} title="Render settings">
          <KVGrid>
            <KV label="Renderer" value={log.renderer ?? '—'} />
            {log.renderer === 'blender' && <>
              <KV label="Engine" value={log.engine_used ?? log.engine ?? '—'} highlight={log.engine_used !== log.engine} />
              <KV label="Samples" value={log.samples?.toString() ?? '—'} />
              <KV label="Device" value={log.cycles_device ?? '—'} />
              <KV label="STL quality" value={log.stl_quality ?? '—'} />
              <KV label="Smooth angle" value={log.smooth_angle != null ? `${log.smooth_angle}°` : '—'} />
              <KV label="Resolution" value={log.width && log.height ? `${log.width}×${log.height}` : '—'} />
            </>}
            {log.renderer === 'threejs' && (
              <KV label="Resolution" value={log.width && log.height ? `${log.width}×${log.height}` : '—'} />
            )}
            <KV label="Output format" value={log.format ?? '—'} />
            {log.fallback && <KV label="Fallback" value="Yes (Pillow placeholder)" highlight />}
          </KVGrid>
        </Section>
      )}

      {/* Timing */}
      {log && (log.total_duration_s != null || log.stl_duration_s != null) && (
        <Section icon={<Clock size={13} />} title="Timing">
          <KVGrid>
            {log.total_duration_s != null && <KV label="Total" value={`${log.total_duration_s}s`} />}
            {log.stl_duration_s != null && <KV label="STEP→STL" value={`${log.stl_duration_s}s`} />}
            {log.render_duration_s != null && <KV label="Render" value={`${log.render_duration_s}s`} />}
            {log.stl_size_bytes != null && <KV label="STL size" value={formatBytes(log.stl_size_bytes)} />}
            {log.output_size_bytes != null && <KV label="PNG size" value={formatBytes(log.output_size_bytes)} />}
            {log.parts_count != null && <KV label="Mesh parts" value={log.parts_count.toString()} />}
          </KVGrid>
        </Section>
      )}

      {/* Blender log */}
      {log?.log_lines && log.log_lines.length > 0 && (
        <Section icon={<Terminal size={13} />} title={`Blender log (${log.log_lines.length} lines)`}>
          <BlenderLog lines={log.log_lines} />
        </Section>
      )}
    </div>
  )
}

function Section({
  icon, title, children,
}: { icon: React.ReactNode; title: string; children: React.ReactNode }) {
  return (
    <div>
      <p className="flex items-center gap-1.5 text-xs font-semibold text-content-muted uppercase tracking-wide mb-2">
        {icon}{title}
      </p>
      {children}
    </div>
  )
}

function KVGrid({ children }: { children: React.ReactNode }) {
  return (
    <div className="grid grid-cols-2 sm:grid-cols-3 gap-x-6 gap-y-1.5">
      {children}
    </div>
  )
}

function KV({ label, value, mono, highlight }: {
  label: string; value: string; mono?: boolean; highlight?: boolean
}) {
  return (
    <div className="flex flex-col">
      <span className="text-[10px] uppercase tracking-wide text-content-muted">{label}</span>
      <span className={`text-xs break-all ${mono ? 'font-mono' : ''} ${highlight ? 'text-status-warning-text font-medium' : 'text-content-secondary'}`}>
        {value}
      </span>
    </div>
  )
}

function BlenderLog({ lines }: { lines: string[] }) {
  return (
    <div className="bg-gray-900 rounded-md overflow-auto max-h-64">
      <pre className="text-xs text-gray-200 p-3 leading-5 whitespace-pre-wrap">
        {lines.map((l, i) => {
          const color =
            l.includes('ERROR') || l.includes('failed') ? 'text-red-400' :
            l.includes('WARNING') || l.includes('warn') ? 'text-yellow-300' :
            l.includes('Saved:') || l.includes('render done') ? 'text-green-400' :
            l.includes('separated into') || l.includes('parts_count') ? 'text-cyan-400' :
            'text-gray-200'
          return (
            <span key={i} className={`block ${color}`}>{l}</span>
          )
        })}
      </pre>
    </div>
  )
}

function RendererBadge({ log }: { log: RenderLog }) {
  if (log.renderer === 'blender') {
    const eng = log.engine_used ?? log.engine ?? ''
    const label = eng.includes('fallback')
      ? `Blender · Cycles (↩ fallback)`
      : `Blender · ${eng}`
    return (
      <span className="text-xs bg-status-info-bg text-status-info-text px-1.5 py-0.5 rounded font-medium">
        {label}
      </span>
    )
  }
  if (log.renderer === 'threejs') {
    return (
      <span className="text-xs bg-purple-100 text-purple-700 px-1.5 py-0.5 rounded font-medium">
        Three.js
      </span>
    )
  }
  return (
    <span className="text-xs bg-surface-muted text-content-secondary px-1.5 py-0.5 rounded font-medium">
      {log.renderer}
    </span>
  )
}

function StatusIcon({ status }: { status: string }) {
  if (status === 'completed') return <CheckCircle2 size={16} className="text-green-500 shrink-0" />
  if (status === 'failed') return <XCircle size={16} className="text-red-500 shrink-0" />
  if (status === 'processing') return <Loader2 size={16} className="animate-spin text-blue-500 shrink-0" />
  return <Clock size={16} className="text-content-muted shrink-0" />
}

function StatCard({ label, value, color }: { label: string; value: number; color: string }) {
  return (
    <div className="card p-4 text-center">
      <p className={`text-2xl font-bold ${color}`}>{value}</p>
      <p className="text-xs text-content-muted mt-0.5">{label}</p>
    </div>
  )
}

function formatBytes(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
  return `${(bytes / (1024 * 1024)).toFixed(2)} MB`
}
