import { useCallback, useEffect, useRef } from 'react';

import { captureException } from '@sentry/react';

import { usePageVisibilityContext } from 'src/contexts/PageVisibilityContext';
import { CDN_URLS } from 'src/services/cdnPingService';
import { type CDNPingResult } from 'src/workers/cdnPingWorker';

const LAST_PING_KEY = 'cdn_ping_last_timestamp';
const ACTIVE_TAB_KEY = 'cdn_ping_active_tab';
const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
// If a tab hasn't refreshed its registration in this time, consider it stale
const REGISTRATION_TIMEOUT_MS = 30 * 1000;

function shouldPing(): boolean {
  try {
    const lastPing = localStorage.getItem(LAST_PING_KEY);
    if (!lastPing) return true;
    const lastPingTime = parseInt(lastPing, 10);
    return Date.now() - lastPingTime >= ONE_WEEK_MS;
  } catch {
    // localStorage might be unavailable
    return false;
  }
}

function markPingComplete(): void {
  try {
    localStorage.setItem(LAST_PING_KEY, Date.now().toString());
  } catch {
    // localStorage might be unavailable
  }
}

function tryRegisterTab(tabId: string): boolean {
  try {
    const existing = localStorage.getItem(ACTIVE_TAB_KEY);
    if (existing) {
      const { id, timestamp } = JSON.parse(existing);
      // If another tab is registered and not stale, don't register
      if (id !== tabId && Date.now() - timestamp < REGISTRATION_TIMEOUT_MS) {
        return false;
      }
    }
    localStorage.setItem(
      ACTIVE_TAB_KEY,
      JSON.stringify({ id: tabId, timestamp: Date.now() }),
    );
    return true;
  } catch {
    return false;
  }
}

function unregisterTab(tabId: string): void {
  try {
    const existing = localStorage.getItem(ACTIVE_TAB_KEY);
    if (existing) {
      const { id } = JSON.parse(existing);
      if (id === tabId) {
        localStorage.removeItem(ACTIVE_TAB_KEY);
      }
    }
  } catch {
    // localStorage might be unavailable
  }
}

/**
 * Hook to manage CDN pinging using Web Workers
 * Pings once per week to detect CDN connectivity issues
 * Only runs on visible tabs and prevents multiple tabs from pinging simultaneously
 */
export function useCDNPing() {
  const workerRef = useRef<Worker | null>(null);
  const tabIdRef = useRef(crypto.randomUUID());

  const handleResults = useCallback((results: CDNPingResult[]) => {
    // Only log failures to Sentry - successes are completely ignored
    const failures = results.filter(r => !r.success);
    if (failures.length > 0) {
      failures.forEach(failure => {
        const error = new Error(`CDN ping failed: ${failure.url}`);
        error.name = 'CDNPingFailure';
        captureException(error, {
          extra: {
            url: failure.url,
            error: failure.error,
            responseTime: failure.responseTime,
            timestamp: failure.timestamp,
          },
          tags: {
            cdn_url: failure.url,
            resource_type: 'cdn',
          },
        });
      });
    }
  }, []);

  const performPing = useCallback(() => {
    if (!workerRef.current) {
      try {
        workerRef.current = new Worker(
          new URL('../workers/cdnPingWorker.ts', import.meta.url),
          { type: 'module' },
        );

        workerRef.current.onmessage = (event: MessageEvent) => {
          if (event.data.type === 'PING_RESULT') {
            const results: CDNPingResult[] = event.data.results;
            handleResults(results);
            markPingComplete();
            unregisterTab(tabIdRef.current);
          }
        };

        workerRef.current.onerror = () => {
          unregisterTab(tabIdRef.current);
        };
      } catch {
        unregisterTab(tabIdRef.current);
        return;
      }
    }

    workerRef.current.postMessage({
      type: 'PING',
      urls: CDN_URLS,
    });
  }, [handleResults]);

  const handleVisibilityChange = useCallback(
    (isVisible: boolean) => {
      if (isVisible) {
        if (shouldPing() && tryRegisterTab(tabIdRef.current)) {
          performPing();
        }
      } else {
        unregisterTab(tabIdRef.current);
      }
    },
    [performPing],
  );

  const { isVisibleRef } = usePageVisibilityContext(handleVisibilityChange);

  useEffect(() => {
    if (isVisibleRef.current) {
      handleVisibilityChange(true);
    }
    return () => {
      unregisterTab(tabIdRef.current);
    };
  }, [handleVisibilityChange, isVisibleRef]);

  // Cleanup worker on unmount
  useEffect(() => {
    return () => {
      if (workerRef.current) {
        workerRef.current.postMessage({ type: 'STOP' });
        workerRef.current.terminate();
        workerRef.current = null;
      }
    };
  }, []);
}
