import { useEffect, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { apiFetch, isPremium } from '../lib/api';
import { useHeadlessScan } from './useHeadlessScan';

const STATUS_POLL_MS = 5 * 60 * 1000; // catches a scan becoming due while the dashboard stays open

type ScheduledScanStatus = {
  status: 'idle' | 'due' | 'running' | 'completed' | 'unavailable';
  cursor?: number;
  total?: number;
};

type ClaimResponse =
  | { claimed: true; token: string; urls: string[]; cursor: number }
  | { claimed: false; status: string };

/**
 * WP-Cron can't run axe-core (no DOM/JS in a PHP request) — it only flips a
 * scan to "due" (see AccessMate_Pro::mark_scheduled_scan_due()). This hook is
 * the other half: while an authorized admin has the AccessMate dashboard
 * open, it claims a due scan and drives it through the exact same
 * useHeadlessScan → runAutoScan() → /axe-scan pipeline PageScanner's Bulk
 * Scan already uses, so Scheduled/Bulk/Individual all produce identical
 * results. No-ops entirely for Free (isPremium false).
 *
 * A claim is a server-side compare-and-swap (see try_claim_scheduled_scan()),
 * so multiple tabs/admins/refreshes can't double-run it — only one wins.
 * Progress is reported after every URL so a closed tab's claim expires and
 * the next session resumes from where it left off, rather than restarting.
 */
export function useScheduledScanRunner(): void {
  const qc = useQueryClient();
  const { scanUrlAsync } = useHeadlessScan();
  const runningRef = useRef(false);

  const { data: status } = useQuery({
    queryKey: ['scheduled-scan-status'],
    queryFn: () => apiFetch<ScheduledScanStatus>('/scheduled-scan/status'),
    enabled: isPremium,
    refetchInterval: STATUS_POLL_MS,
    staleTime: 0,
  });

  useEffect(() => {
    if (!isPremium || runningRef.current) return;
    if (status?.status !== 'due' && status?.status !== 'running') return;

    runningRef.current = true;

    (async () => {
      try {
        const claim = await apiFetch<ClaimResponse>('/scheduled-scan/claim', { method: 'POST' });
        if (!claim.claimed) return; // another session already owns it, or nothing to do

        for (let i = claim.cursor; i < claim.urls.length; i++) {
          await scanUrlAsync(claim.urls[i]).catch(() => {}); // a broken page shouldn't block the rest of the batch
          const progress = await apiFetch<{ ok: boolean }>('/scheduled-scan/progress', {
            method: 'POST',
            body: JSON.stringify({ token: claim.token, cursor: i + 1 }),
          }).catch(() => ({ ok: false }));
          if (!progress.ok) return; // lease lost to another session — stop, don't fight over it
        }

        await apiFetch('/scheduled-scan/complete', {
          method: 'POST',
          body: JSON.stringify({ token: claim.token }),
        }).catch(() => undefined);

        qc.invalidateQueries({ queryKey: ['page-scans'] });
        qc.invalidateQueries({ queryKey: ['report'] });
        qc.invalidateQueries({ queryKey: ['scheduled-scan-status'] });
      } finally {
        runningRef.current = false;
      }
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [status?.status]);
}
