/* WorkerPulse — single worker heartbeat tile.
 *
 * State derives from:
 *   • last activity is fresher than the worker's expected cadence → ok / pending
 *   • last activity stale → idle (worker quiet, not necessarily broken)
 *   • any failures in the last hour → warn (degraded)
 *   • all 1h runs failing → error
 *
 * Per-worker freshness thresholds:
 *   • Analyzer        — 5 min (poll every 2s, gets work intermittently)
 *   • RMM Overshell   — 10 min
 *   • Sync scheduler  — 60 min (cron-driven; quietest worker) */

'use client';

import { Card, CardContent } from '@/components/ui/card';
import { StatusLight, type StatusLightState } from '@/components/ui/status-light';
import { ActivitySparkline } from '@/components/status/activity-sparkline';

interface ActivityBucket {
  hour: string;
  success: number;
  failure: number;
}

interface WorkerSnapshot {
  name: string;
  lastActivity: string | null;
  inFlight: number;
  oneHour: { success: number; failure: number };
  activity24h?: ActivityBucket[];
}

interface WorkerPulseProps {
  worker: WorkerSnapshot;
  /** Stale threshold in minutes; varies per worker. */
  freshnessMinutes?: number;
}

function relTime(iso: string | null): string {
  if (!iso) return 'never';
  const ms = Date.now() - new Date(iso).getTime();
  if (ms < 0) return 'just now';
  const min = Math.floor(ms / 60000);
  if (min < 1) return 'just now';
  if (min < 60) return `${min} min ago`;
  const hr = Math.floor(min / 60);
  if (hr < 48) return `${hr} h ago`;
  const day = Math.floor(hr / 24);
  return `${day} d ago`;
}

export function WorkerPulse({ worker, freshnessMinutes = 30 }: WorkerPulseProps) {
  const { lastActivity, inFlight, oneHour } = worker;
  const fresh =
    lastActivity != null &&
    Date.now() - new Date(lastActivity).getTime() < freshnessMinutes * 60_000;

  let state: StatusLightState;
  let stateLabel: string;
  if (oneHour.failure > 0 && oneHour.success === 0) {
    state = 'error';
    stateLabel = 'failing';
  } else if (oneHour.failure > 0) {
    state = 'warn';
    stateLabel = 'degraded';
  } else if (inFlight > 0) {
    state = 'pending';
    stateLabel = 'in flight';
  } else if (fresh) {
    state = 'ok';
    stateLabel = 'ok';
  } else {
    state = 'idle';
    stateLabel = 'idle';
  }

  return (
    <Card>
      <CardContent className="pt-4 pb-3 space-y-3">
        <div className="flex items-start justify-between">
          <div>
            <p className="text-sm font-medium leading-none">{worker.name}</p>
            <p className="text-xs text-muted-foreground mt-1 capitalize">{stateLabel}</p>
          </div>
          <StatusLight state={state} size="lg" pulse={state === 'pending'} label={stateLabel} />
        </div>

        <div className="grid grid-cols-3 gap-2 text-center">
          <Stat label="In flight" value={inFlight} />
          <Stat label="Ok · 1h" value={oneHour.success} />
          <Stat label="Fail · 1h" value={oneHour.failure} tone={oneHour.failure > 0 ? 'error' : 'default'} />
        </div>

        {worker.activity24h && worker.activity24h.length > 0 && (
          <div className="space-y-1">
            <ActivitySparkline data={worker.activity24h} />
            <div className="flex justify-between text-[10px] text-muted-foreground num">
              <span>24h ago</span>
              <span>now</span>
            </div>
          </div>
        )}

        <p className="text-xs text-muted-foreground">
          Last activity <span className="num">{relTime(lastActivity)}</span>
        </p>
      </CardContent>
    </Card>
  );
}

function Stat({
  label,
  value,
  tone = 'default',
}: {
  label: string;
  value: number;
  tone?: 'default' | 'error';
}) {
  return (
    <div className="rounded-sm bg-muted/40 py-1.5 px-2">
      <p
        className={
          'num text-base ' + (tone === 'error' ? 'text-destructive' : 'text-foreground')
        }
      >
        {value}
      </p>
      <p className="text-[10px] uppercase tracking-wider text-muted-foreground">
        {label}
      </p>
    </div>
  );
}
