import { useState } from 'react';
import type { AgentAction, AgentView, WatchState } from '@stream-control/shared';
import { formatBytes, formatPercent, formatRelative, formatTimecode } from '../format';

interface Props {
  agent: AgentView;
  selected: boolean;
  onToggleSelect: (id: string) => void;
  onCommand: (id: string, action: AgentAction, params?: Record<string, unknown>) => Promise<void>;
  onOpenSettings: (agent: AgentView) => void;
}

export function AgentCard({ agent, selected, onToggleSelect, onCommand, onOpenSettings }: Props) {
  const [pending, setPending] = useState<AgentAction | null>(null);
  const { status } = agent;

  async function run(action: AgentAction, params?: Record<string, unknown>) {
    setPending(action);
    try {
      await onCommand(agent.id, action, params);
    } finally {
      setPending(null);
    }
  }

  const busy = pending !== null;
  const obsReady = agent.online && status.obsConnected;

  const watch = status.watch;
  const pausedLabel = watch?.autoPaused ? 'Pause · show privé' : 'En pause';

  const state = !agent.online
    ? { label: 'Hors-ligne', tone: 'offline' as const }
    : !status.obsConnected
      ? { label: 'OBS déconnecté', tone: 'warn' as const }
      : status.recording
        ? {
            label: status.recordPaused ? pausedLabel : 'Enregistre',
            tone: status.recordPaused ? ('warn' as const) : ('rec' as const),
          }
        : { label: 'Prêt', tone: 'ok' as const };

  return (
    <article className={`card tone-${state.tone}${selected ? ' selected' : ''}`}>
      <header className="card-head">
        <label className="select">
          <input
            type="checkbox"
            checked={selected}
            onChange={() => onToggleSelect(agent.id)}
            aria-label={`Sélectionner ${agent.name}`}
          />
        </label>
        <div className="identity">
          <h2>{agent.name}</h2>
          <span className="muted small">
            {agent.hostname ?? '—'} · {agent.platform}
            {agent.agentVersion ? ` · v${agent.agentVersion}` : ''}
          </span>
        </div>
        <span className={`badge ${state.tone}`}>{state.label}</span>
        <button className="icon" onClick={() => onOpenSettings(agent)} title="Configuration">
          ⚙
        </button>
      </header>

      {status.obsError && !status.obsConnected && (
        <p className="error small">{status.obsError}</p>
      )}

      {watch?.enabled && (
        <WatchStrip
          watch={watch}
          busy={busy}
          onCheck={() => void run('watch.check')}
          onFullscreen={() => void run('hotkey.fullscreen')}
        />
      )}

      <div className="metrics">
        <Metric label="Durée" value={formatTimecode(status.recordTimecode)} mono />
        <Metric label="Fichier" value={formatBytes(status.recordBytes)} />
        <Metric label="Disque libre" value={formatBytes(status.diskFreeBytes)} />
        <Metric label="CPU OBS" value={formatPercent(status.cpuUsage)} />
        <Metric label="FPS" value={status.fps ? status.fps.toFixed(0) : '—'} />
        <Metric label="Frames perdues" value={String(status.droppedFrames ?? '—')} />
      </div>

      <div className="row">
        <label className="field grow">
          <span>Scène</span>
          <select
            value={status.currentScene ?? ''}
            disabled={!obsReady || busy || status.scenes.length === 0}
            onChange={(event) => void run('scene.set', { scene: event.target.value })}
          >
            {status.scenes.length === 0 && <option value="">— aucune scène —</option>}
            {status.scenes.map((scene) => (
              <option key={scene} value={scene}>
                {scene}
              </option>
            ))}
          </select>
        </label>
      </div>

      <div className="actions">
        {status.recording ? (
          <>
            <button className="danger" disabled={busy} onClick={() => void run('record.stop')}>
              ■ Arrêter
            </button>
            {status.recordPaused ? (
              <button disabled={busy} onClick={() => void run('record.resume')}>
                ▶ Reprendre
              </button>
            ) : (
              <button disabled={busy} onClick={() => void run('record.pause')}>
                ⏸ Pause
              </button>
            )}
            <button disabled={busy} onClick={() => void run('record.split')}>
              ✂ Découper
            </button>
          </>
        ) : (
          <button className="primary" disabled={!obsReady || busy} onClick={() => void run('record.start')}>
            ● Enregistrer
          </button>
        )}

        {status.streaming ? (
          <button className="danger ghost" disabled={busy} onClick={() => void run('stream.stop')}>
            Arrêter le stream
          </button>
        ) : (
          <button className="ghost" disabled={!obsReady || busy} onClick={() => void run('stream.start')}>
            Lancer le stream
          </button>
        )}

        {status.obsConnected ? (
          <button className="ghost" disabled={!agent.online || busy} onClick={() => void run('obs.disconnect')}>
            Détacher OBS
          </button>
        ) : (
          <button className="ghost" disabled={!agent.online || busy} onClick={() => void run('obs.connect')}>
            Connecter OBS
          </button>
        )}
      </div>

      <footer className="card-foot muted small">
        <span title={status.recordDirectory ?? ''}>
          {status.lastRecordingPath
            ? `Dernier fichier : ${basename(status.lastRecordingPath)}`
            : (status.recordDirectory ?? 'Dossier inconnu')}
        </span>
        <span>vu {formatRelative(agent.lastSeenAt)}</span>
      </footer>
    </article>
  );
}

const WATCH_LABELS: Record<WatchState['state'], { text: string; tone: string }> = {
  public: { text: 'public', tone: 'ok' },
  private: { text: 'show privé', tone: 'rec' },
  offline: { text: 'hors-ligne', tone: 'offline' },
  unknown: { text: 'inconnu', tone: 'offline' },
};

function WatchStrip({
  watch,
  busy,
  onCheck,
  onFullscreen,
}: {
  watch: WatchState;
  busy: boolean;
  onCheck: () => void;
  onFullscreen: () => void;
}) {
  const info = WATCH_LABELS[watch.state];
  const stale = watch.lastCheckedAt > 0 && Date.now() - watch.lastCheckedAt > 60_000;

  return (
    <div className="watch">
      <div className="watch-head">
        <span className={`badge ${info.tone}`}>{info.text}</span>
        <span className="watch-name" title={`${watch.provider} · ${watch.username}`}>
          {watch.username || '(aucun pseudo)'}
        </span>
        <div className="spacer" />
        <button className="icon" disabled={busy} onClick={onCheck} title="Sonder maintenant">
          ⟳
        </button>
        <button className="icon" disabled={busy} onClick={onFullscreen} title="Remettre en plein écran">
          ⛶
        </button>
      </div>

      {watch.lastError ? (
        <span className="small error">Sonde en échec : {watch.lastError}</span>
      ) : (
        <span className="small muted">
          {watch.rawStatus ? `statut brut « ${watch.rawStatus} »` : 'pas encore sondé'}
          {watch.autoPaused && ' · pause automatique active'}
          {stale && ' · dernière sonde ancienne'}
        </span>
      )}
    </div>
  );
}

function Metric({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div className="metric">
      <span className="metric-label">{label}</span>
      <span className={`metric-value${mono ? ' mono' : ''}`}>{value}</span>
    </div>
  );
}

function basename(filePath: string): string {
  const parts = filePath.split(/[\\/]/);
  return parts[parts.length - 1] ?? filePath;
}
