import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useWorkerStatus } from '../../hooks/useWorkerStatus';
import { useActivePet } from '../../hooks/useActivePet';
import { usePetFrameAnalysis } from '../../hooks/usePetFrameAnalysis';
import { PetSprite } from '../pets/PetSprite';
import type { WorkerStatusBackendRow } from '../../api';

function usePrefersReducedMotion(): boolean {
  if (typeof window === 'undefined' || !window.matchMedia) return false;
  return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

export function WorkerStatusWidget() {
  const { t } = useTranslation('dashboard');
  const { workers, isLoading, isError } = useWorkerStatus();

  if (isLoading) return <div className="text-xs text-slate-500 p-3">{t('worker.loading')}</div>;
  if (isError) return <div className="text-xs text-red-600 p-3">{t('worker.fetchError')}</div>;
  if (workers.length === 0) {
    return <div className="text-xs text-slate-500 p-3">{t('worker.empty')}</div>;
  }

  return (
    <div className="flex flex-col gap-1 p-2 overflow-auto h-full">
      {workers.map((w) => (
        <WorkerRow
          key={w.id}
          workerId={w.id}
          name={w.name}
          roles={w.roles}
          state={w.state}
          proxy={w.proxy}
          backends={w.backends}
          busySlots={w.busySlots}
          totalSlots={w.totalSlots}
          online={w.online}
        />
      ))}
    </div>
  );
}

function WorkerRow({
  workerId, name, roles, state, proxy, backends, busySlots, totalSlots, online,
}: {
  workerId: string;
  name: string;
  roles: string[];
  state: 'idle' | 'running';
  proxy: boolean;
  backends: WorkerStatusBackendRow[] | undefined;
  /** Direct workers carry slot pressure at the row level; proxy workers leave these undefined and surface per-backend pressure in `backends[]`. */
  busySlots?: number;
  totalSlots?: number;
  online?: boolean;
}) {
  const { t } = useTranslation('dashboard');
  // Default expanded so the operator sees backend granularity on first
  // load. Collapse is a local-only convenience for noisy pools.
  const [collapsed, setCollapsed] = useState(false);

  const { data: pet } = useActivePet(workerId);
  const framesPerRow = usePetFrameAnalysis(
    pet?.spriteUrl ?? null,
    pet?.gridCols ?? null,
    pet?.gridRows ?? null,
  );
  const systemReducedMotion = usePrefersReducedMotion();
  const petReducedMotion = (pet?.settings as { reducedMotion?: boolean } | undefined)?.reducedMotion ?? false;
  const reducedMotion = petReducedMotion || systemReducedMotion;

  const isOffline = online === false;
  const dotColor = isOffline
    ? 'bg-red-400'
    : state === 'running' ? 'bg-emerald-500' : 'bg-slate-300';
  const showPet = pet?.pet && pet.imageUrl;
  const hasBackends = proxy && Array.isArray(backends) && backends.length > 0;
  const proxyAriaLabel = hasBackends ? (collapsed ? t('worker.expand') : t('worker.collapse')) : undefined;
  // Slot caption: only render when the registry has produced a usable
  // totalSlots figure. Unset (= no probe row) and 0 (= probe row but
  // /slots was empty) both suppress the caption so we don't paint a
  // confusing `(busy/0)`.
  const slotsLabel = typeof totalSlots === 'number' && totalSlots > 0
    ? `${busySlots ?? 0}/${totalSlots}`
    : null;

  return (
    <div>
      <div className="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-surface-2">
        <div className="w-8 h-8 flex-shrink-0 flex items-center justify-center">
          {showPet ? (
            <PetSprite
              name={pet.pet!.name}
              imageUrl={pet.imageUrl}
              frameWidth={pet.frameWidth}
              frameHeight={pet.frameHeight}
              gridCols={pet.gridCols}
              gridRows={pet.gridRows}
              framesPerRow={framesPerRow}
              state={state}
              size={32}
              reducedMotion={reducedMotion}
            />
          ) : (
            <span className={`w-3 h-3 rounded-full ${dotColor}`} aria-label={state} />
          )}
        </div>
        <div className="flex-1 min-w-0">
          <div className="text-xs font-medium text-slate-800 truncate flex items-center gap-1">
            {hasBackends && (
              <button
                type="button"
                onClick={() => setCollapsed((v) => !v)}
                aria-label={proxyAriaLabel}
                aria-expanded={!collapsed}
                className="w-3 text-slate-400 leading-none"
              >
                {collapsed ? '▶' : '▼'}
              </button>
            )}
            <span className="truncate">{name}</span>
            {proxy && (
              <span className="px-1 py-0.5 rounded text-[9px] font-medium bg-violet-50 dark:bg-violet-500/15 text-violet-700 dark:text-violet-300 leading-none">
                proxy
              </span>
            )}
          </div>
          {roles.length > 0 && (
            <div className="text-[10px] text-slate-500 font-mono truncate">{roles.join(', ')}</div>
          )}
        </div>
        <div className="flex items-center gap-1 text-[11px] font-mono">
          <span className={`w-2 h-2 rounded-full ${dotColor}`} />
          {isOffline ? (
            <span className="text-red-600">offline</span>
          ) : (
            <>
              <span className="text-slate-600">{state}</span>
              {slotsLabel && (
                <span className="text-slate-400">({slotsLabel})</span>
              )}
            </>
          )}
        </div>
      </div>
      {hasBackends && !collapsed && (
        <div className="ml-4 border-l border-slate-100 pl-2 flex flex-col gap-0.5 mb-1">
          {backends!.map((b) => (
            <BackendRow key={b.id} workerId={workerId} backend={b} reducedMotion={reducedMotion} />
          ))}
        </div>
      )}
    </div>
  );
}

function BackendRow({
  workerId, backend, reducedMotion,
}: {
  workerId: string;
  backend: WorkerStatusBackendRow;
  reducedMotion: boolean;
}) {
  // useActivePet(workerId, backendId) follows the per-Phase A priority:
  // workerPets[backend.id] → workerPets[workerId] → global default.
  // This gives the operator a per-backend pet override while still
  // falling back to the proxy-level pet when no override exists.
  const { data: pet } = useActivePet(workerId, backend.id);
  const framesPerRow = usePetFrameAnalysis(
    pet?.spriteUrl ?? null,
    pet?.gridCols ?? null,
    pet?.gridRows ?? null,
  );
  const dotColor = backend.online === false
    ? 'bg-red-400'
    : backend.state === 'running'
      ? 'bg-emerald-500'
      : 'bg-slate-300';
  const showPet = pet?.pet && pet.imageUrl;
  // Slot caption: only render when the registry has a usable totalSlots
  // figure. Zero (= unprobed) renders as bare `(busy/0)` which is
  // confusing, so we suppress it until the first probe lands.
  const slotsLabel = backend.totalSlots > 0
    ? `${backend.busySlots}/${backend.totalSlots}`
    : null;

  return (
    <div className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-surface-2">
      <div className="w-6 h-6 flex-shrink-0 flex items-center justify-center">
        {showPet ? (
          <PetSprite
            name={pet.pet!.name}
            imageUrl={pet.imageUrl}
            frameWidth={pet.frameWidth}
            frameHeight={pet.frameHeight}
            gridCols={pet.gridCols}
            gridRows={pet.gridRows}
            framesPerRow={framesPerRow}
            state={backend.state}
            size={24}
            reducedMotion={reducedMotion}
          />
        ) : (
          <span className={`w-2 h-2 rounded-full ${dotColor}`} aria-label={backend.state} />
        )}
      </div>
      <div className="flex-1 min-w-0">
        <div className="text-[11px] text-slate-700 font-mono truncate">{backend.id}</div>
      </div>
      <div className="flex items-center gap-1 text-[10px] font-mono">
        <span className={`w-1.5 h-1.5 rounded-full ${dotColor}`} />
        {backend.online === false ? (
          <span className="text-red-600">offline</span>
        ) : (
          <>
            <span className="text-slate-600">{backend.state}</span>
            {slotsLabel && (
              <span className="text-slate-400">({slotsLabel})</span>
            )}
          </>
        )}
      </div>
    </div>
  );
}
