import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';

import { MitreTagPicker } from '@/components/MitreTagPicker';
import { Alert } from '@/components/ui/Alert';
import { Button } from '@/components/ui/Button';
import { Card } from '@/components/ui/Card';
import { SectionHeader } from '@/components/ui/SectionHeader';
import { Tag } from '@/components/ui/Tag';
import { ApiError, apiGet, apiPost } from '@/lib/api';
import { useAuth } from '@/lib/auth';
import { mitreKeys, type MitreStatus, type MitreTag } from '@/lib/mitre';

export function MitrePage() {
  const { state } = useAuth();
  const qc = useQueryClient();
  const [selected, setSelected] = useState<MitreTag[]>([]);
  const [syncResult, setSyncResult] = useState<string | null>(null);
  const [syncError, setSyncError] = useState<string | null>(null);

  const status = useQuery({
    queryKey: mitreKeys.status,
    queryFn: () => apiGet<MitreStatus>('/mitre/status'),
  });

  const sync = useMutation({
    mutationFn: () => apiPost<Record<string, unknown>>('/mitre/sync'),
    onMutate: () => {
      setSyncResult(null);
      setSyncError(null);
    },
    onSuccess: async (res) => {
      const counts = `${res.tactics_upserted} tactics, ${res.techniques_upserted} techniques, ${res.subtechniques_upserted} subtechniques`;
      setSyncResult(`Sync completed in ${(res as { duration_ms: number }).duration_ms / 1000}s — ${counts}.`);
      await qc.invalidateQueries({ queryKey: ['mitre'] });
    },
    onError: (e) => {
      if (e instanceof ApiError) {
        const p = e.payload as { error?: string; message?: string } | null;
        setSyncError(p?.message ?? p?.error ?? `HTTP ${e.status}`);
      } else {
        setSyncError(e instanceof Error ? e.message : 'Sync failed');
      }
    },
  });

  return (
    <>
      <SectionHeader
        prefix="MITRE"
        highlight="ATT&CK"
        accent="cyan"
        description="Reference catalogue: tactics, techniques, sub-techniques. Tag picker reusable by tests and missions."
      />

      <div className="grid gap-4 mb-6 [grid-template-columns:repeat(auto-fill,minmax(360px,1fr))]">
        <Card accent="cyan" title="Source" sub={status.data?.version ? `version ${status.data.version}` : '—'}>
          <p>
            URL:{' '}
            <code className="accent-fill-cyan px-2 py-[2px] rounded-sm font-mono text-4xs break-all">
              {status.data?.source_url ?? status.data?.default_url ?? '—'}
            </code>
          </p>
          <p className="mt-2">
            Last sync:{' '}
            <code
              className="accent-fill-cyan px-2 py-[2px] rounded-sm font-mono text-4xs"
              data-testid="mitre-last-sync"
            >
              {status.data?.last_sync ?? 'never'}
            </code>
          </p>
        </Card>

        {state.user?.is_admin && (
          <Card accent="orange" title="Sync" sub="re-pull the bundle from the configured source">
            <p className="text-2xs text-text-dim mb-3">
              The seed CLI runs the same logic; trigger from here only if the URL is reachable from the api container.
            </p>
            <Button
              accent="orange"
              onClick={() => sync.mutate()}
              disabled={sync.isPending}
              data-testid="mitre-sync"
            >
              {sync.isPending ? 'Syncing…' : 'Trigger MITRE sync'}
            </Button>
            {syncResult && <Alert accent="green" className="mt-3">{syncResult}</Alert>}
            {syncError && <Alert accent="red" className="mt-3">{syncError}</Alert>}
          </Card>
        )}
      </div>

      <SectionHeader prefix="Tag" highlight="Picker" accent="orange" />
      {/* Full-bleed the matrix beyond max-w-page so it uses the full viewport
       * width. `calc(50% - 50vw)` is the canonical CSS recipe: the element's
       * left edge slides back to viewport x=0 regardless of how big the
       * outer max-w-page container is. `px-[60px]` mirrors the page padding
       * so cells don't touch the viewport edge. */}
      <div
        className="px-[60px]"
        style={{
          marginLeft: 'calc(50% - 50vw)',
          marginRight: 'calc(50% - 50vw)',
          width: '100vw',
        }}
      >
        <MitreTagPicker value={selected} onChange={setSelected} />
      </div>

      {selected.length > 0 && (
        <Card accent="purple" className="mt-6" title="Selected (preview payload)">
          <pre className="text-2xs text-text-bright whitespace-pre-wrap" data-testid="mitre-selected-json">
            {JSON.stringify(selected, null, 2)}
          </pre>
        </Card>
      )}

      {selected.length === 0 && (
        <p className="mt-3 font-mono text-2xs text-text-dim">
          Click any cell to toggle. Use <span className="text-purple">▸</span> to reveal sub-techniques inline. Hover a cell for its <code className="text-purple">external_id</code>. Selections accumulate.
        </p>
      )}

      <div className="mt-4">
        <Tag accent="cyan">Tactic</Tag>
        <Tag accent="orange">Technique</Tag>
        <Tag accent="purple">Sub-technique</Tag>
      </div>
    </>
  );
}
