/**
 * A2aDelegationsForm.tsx — Settings → A2A Delegations
 *
 * Lists the current user's A2A delegations (granted access tokens issued to
 * external agents) and lets them revoke any live delegation.
 * Revocation takes effect immediately: the token is invalidated and any
 * running tasks created under that delegation are cancelled.
 *
 * Consumes:
 *   GET  /api/local/a2a/delegations
 *   POST /api/local/a2a/delegations/:id/revoke
 */
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

// ── Types ──────────────────────────────────────────────────────────────────

interface Delegation {
  id: string;
  clientId: string;
  clientName: string;
  grantedSpaceIds: string[];
  grantedSkills: string[];
  expiresAt: string | null;
  revokedAt: string | null;
  createdAt: string;
  live: boolean;
}

interface DelegationsResponse {
  delegations: Delegation[];
}

interface RevokeResponse {
  status: 'revoked' | 'already-revoked';
  cancelledJobs?: number;
}

// ── API helpers ────────────────────────────────────────────────────────────

async function fetchDelegations(): Promise<DelegationsResponse> {
  const res = await fetch('/api/local/a2a/delegations');
  if (!res.ok) throw new Error(String(res.status));
  return res.json();
}

async function postRevoke(id: string): Promise<RevokeResponse> {
  const res = await fetch(`/api/local/a2a/delegations/${encodeURIComponent(id)}/revoke`, {
    method: 'POST',
  });
  if (!res.ok) {
    const body = await res.json().catch(() => ({})) as { error?: string };
    throw new Error(body.error ?? res.statusText);
  }
  return res.json();
}

// ── Chip ──────────────────────────────────────────────────────────────────

function Chip({ label }: { label: string }) {
  return (
    <span className="inline-block rounded bg-surface px-1.5 py-0.5 text-xs text-slate-600 border border-hairline">
      {label}
    </span>
  );
}

// ── DelegationRow ──────────────────────────────────────────────────────────

interface DelegationRowProps {
  delegation: Delegation;
  confirmId: string | null;
  onRequestConfirm: (id: string) => void;
  onCancelConfirm: () => void;
  onConfirmRevoke: (id: string) => void;
  isPending: boolean;
  lastSuccessId: string | null;
  cancelledJobs: number | null;
}

function DelegationRow({
  delegation: d,
  confirmId,
  onRequestConfirm,
  onCancelConfirm,
  onConfirmRevoke,
  isPending,
  lastSuccessId,
  cancelledJobs,
}: DelegationRowProps) {
  const { t } = useTranslation('a2a');

  const isConfirming = confirmId === d.id;
  const justRevoked = lastSuccessId === d.id;

  return (
    <div className="rounded-md border border-hairline p-4 space-y-2">
      {/* Header: client name + status badge */}
      <div className="flex items-start justify-between gap-2">
        <span className="font-medium text-sm text-slate-800">
          {d.clientName || d.clientId}
        </span>
        {d.live ? (
          <span className="flex-shrink-0 rounded-full bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-700 border border-emerald-200">
            {t('delegations.badge.live')}
          </span>
        ) : (
          <span
            data-testid={`revoked-badge-${d.id}`}
            className="flex-shrink-0 rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-500 border border-slate-200"
          >
            {t('delegations.badge.revoked')}
          </span>
        )}
      </div>

      {/* Chips: granted spaces */}
      {d.grantedSpaceIds.length > 0 && (
        <div className="flex flex-wrap gap-1">
          <span className="text-xs text-slate-400 mr-1">{t('delegations.field.grantedSpaces')}:</span>
          {d.grantedSpaceIds.map((s) => <Chip key={s} label={s} />)}
        </div>
      )}

      {/* Chips: granted skills */}
      {d.grantedSkills.length > 0 && (
        <div className="flex flex-wrap gap-1">
          <span className="text-xs text-slate-400 mr-1">{t('delegations.field.grantedSkills')}:</span>
          {d.grantedSkills.map((s) => <Chip key={s} label={s} />)}
        </div>
      )}

      {/* Metadata: created + expiry */}
      <div className="flex flex-wrap gap-4 text-xs text-slate-400">
        <span>
          {t('delegations.field.created')}:{' '}
          {new Date(d.createdAt).toLocaleDateString()}
        </span>
        <span>
          {t('delegations.field.expires')}:{' '}
          {d.expiresAt
            ? new Date(d.expiresAt).toLocaleDateString()
            : t('delegations.field.noExpiry')}
        </span>
      </div>

      {/* Just-revoked success message */}
      {justRevoked && (
        <p className="text-xs text-emerald-600">
          {t('delegations.revokeSuccess')}
          {cancelledJobs != null && cancelledJobs > 0 && (
            <>{' '}{t('delegations.cancelledJobs', { count: cancelledJobs })}</>
          )}
        </p>
      )}

      {/* Revoke / confirm buttons (live rows only) */}
      {d.live && (
        <div className="flex items-center gap-2 pt-1">
          {isConfirming ? (
            <>
              <button
                type="button"
                onClick={() => onConfirmRevoke(d.id)}
                disabled={isPending}
                className="rounded px-3 py-1 text-xs font-medium bg-red-600 text-white hover:bg-red-700 disabled:opacity-50 transition-colors"
              >
                {t('delegations.confirmRevoke')}
              </button>
              <button
                type="button"
                onClick={onCancelConfirm}
                disabled={isPending}
                className="rounded px-3 py-1 text-xs text-slate-600 hover:bg-surface transition-colors"
              >
                {t('delegations.cancel')}
              </button>
            </>
          ) : (
            <button
              type="button"
              onClick={() => onRequestConfirm(d.id)}
              disabled={isPending}
              className="rounded px-3 py-1 text-xs font-medium text-red-600 border border-red-200 hover:bg-red-50 disabled:opacity-50 transition-colors"
            >
              {t('delegations.revoke')}
            </button>
          )}
        </div>
      )}
    </div>
  );
}

// ── A2aDelegationsForm ─────────────────────────────────────────────────────

export function A2aDelegationsForm() {
  const { t } = useTranslation('a2a');
  const queryClient = useQueryClient();

  const [confirmId, setConfirmId] = useState<string | null>(null);
  const [lastSuccessId, setLastSuccessId] = useState<string | null>(null);
  const [lastCancelledJobs, setLastCancelledJobs] = useState<number | null>(null);
  const [errorMsg, setErrorMsg] = useState<string | null>(null);

  const { data, isLoading, error } = useQuery<DelegationsResponse>({
    queryKey: ['a2a-delegations'],
    queryFn: fetchDelegations,
  });

  const revokeMutation = useMutation({
    mutationFn: postRevoke,
    onSuccess: (result, id) => {
      setLastSuccessId(id);
      setLastCancelledJobs(result.cancelledJobs ?? 0);
      setConfirmId(null);
      setErrorMsg(null);
      void queryClient.invalidateQueries({ queryKey: ['a2a-delegations'] });
    },
    onError: () => {
      setConfirmId(null);
      setErrorMsg(t('delegations.err.revoke'));
    },
  });

  if (isLoading) {
    return (
      <div className="max-w-2xl">
        <p className="text-sm text-slate-400">{t('delegations.loading')}</p>
      </div>
    );
  }

  if (error) {
    return (
      <div className="max-w-2xl">
        <p className="text-sm text-red-500">{t('delegations.err.load')}</p>
      </div>
    );
  }

  const delegations = data?.delegations ?? [];

  return (
    <div className="max-w-2xl space-y-4">
      <div>
        <h2 className="text-base font-semibold text-slate-800">{t('delegations.title')}</h2>
        <p className="mt-1 text-xs text-slate-500">{t('delegations.subtitle')}</p>
      </div>

      {errorMsg && (
        <p className="text-sm text-red-500">{errorMsg}</p>
      )}

      {delegations.length === 0 ? (
        <div className="rounded-md border border-hairline p-4 space-y-1">
          <p className="text-sm font-medium text-slate-700">{t('delegations.empty')}</p>
          <p className="text-xs text-slate-400">{t('delegations.emptyExplain')}</p>
        </div>
      ) : (
        <div className="space-y-3">
          {delegations.map((d) => (
            <DelegationRow
              key={d.id}
              delegation={d}
              confirmId={confirmId}
              onRequestConfirm={setConfirmId}
              onCancelConfirm={() => setConfirmId(null)}
              onConfirmRevoke={(id) => revokeMutation.mutate(id)}
              isPending={revokeMutation.isPending}
              lastSuccessId={lastSuccessId}
              cancelledJobs={lastCancelledJobs}
            />
          ))}
        </div>
      )}
    </div>
  );
}
