'use client';

import { useQuery } from '@tanstack/react-query';
import { useEffect, useRef } from 'react';

import { SONGIFY_CONFIG } from '@/config/songify';
import { useApiClient } from '@/lib/apiClient';
import { SongifyProjectStatus, SongifyStatusData } from '@/types/songify';

import { songifyKeys } from './keys';

export interface UseSongifyStatusPollingOptions {
  songifyId: string | null;
  initialStatus: SongifyProjectStatus;
  onStatusUpdate: (songifyId: string, statusData: SongifyStatusData) => void;
  isProjectStale: (songifyId: string) => boolean;
  enabled?: boolean;
}

export function useSongifyStatusPolling({
  songifyId,
  initialStatus,
  onStatusUpdate,
  isProjectStale,
  enabled = true,
}: UseSongifyStatusPollingOptions) {
  const hasReachedTerminalState = useRef(false);
  const apiClient = useApiClient();
  // Check if status is terminal
  const isTerminalStatus = (status: string) => {
    return [
      'completed',
      'failed_expected',
      'failed_system',
      'cancelled',
    ].includes(status);
  };

  // Reset terminal state when songifyId changes
  useEffect(() => {
    hasReachedTerminalState.current = false;

    // If we start with a terminal status, mark it immediately
    if (isTerminalStatus(initialStatus)) {
      hasReachedTerminalState.current = true;
    }
  }, [songifyId, initialStatus]);

  const statusQuery = useQuery({
    queryKey: songifyKeys.status(songifyId || ''),
    queryFn: async () => {
      if (!songifyId) throw new Error('No songify ID provided');

      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 10000);

      try {
        const { data, error, response } = await apiClient.GET(
          `/api/songify/{request_id}/status`,
          {
            params: { path: { request_id: songifyId } },
            signal: controller.signal, // Pass abort signal for timeout
          }
        );

        clearTimeout(timeoutId);

        // Handle 404 errors for stale projects before throwing
        if (response.status === 404) {
          if (isProjectStale(songifyId) && !hasReachedTerminalState.current) {
            // Project is older than 15 minutes and not in terminal state - mark as failed
            const failedStatusData: SongifyStatusData = {
              status: 'failed_system',
              terminal: true,
              message:
                'Project timed out after 15 minutes, stopped waiting for updates.',
              occurred_at: new Date().toISOString(),
              updated_at: new Date().toISOString(),
            };

            onStatusUpdate(songifyId, failedStatusData);
            hasReachedTerminalState.current = true;

            return failedStatusData;
          }
        }

        // Check for errors (non-404 errors)
        if (error || !data) {
          throw new Error(
            `Failed to poll status: ${response} ${JSON.stringify(error)}`
          );
        }
        const normalizedData = data as SongifyStatusData;

        // Update status via callback
        onStatusUpdate(songifyId, normalizedData);

        // Check if we've reached a terminal state
        hasReachedTerminalState.current = normalizedData.terminal;

        return normalizedData;
      } catch (error) {
        clearTimeout(timeoutId);
        console.error(`Failed to poll status for project ${songifyId}:`, error);
        throw error;
      }
    },
    enabled: enabled && !!songifyId && !hasReachedTerminalState.current,
    refetchInterval: (query) => {
      // Stop polling if we've reached a terminal state
      if (hasReachedTerminalState.current) return false;
      const data = query.state.data;
      if (data && (data.terminal || isTerminalStatus(data.status)))
        return false;
      return SONGIFY_CONFIG.POLLING_INTERVAL;
    },
    refetchIntervalInBackground: true,
    retry: (failureCount, error) => {
      // Don't retry 404 errors (they're already handled in queryFn)
      if (error instanceof Error && error.message.includes('404')) {
        return false;
      }
      // Retry up to 3 times for other errors
      return failureCount < 3;
    },
  });

  return {
    statusData: statusQuery.data,
    isPolling: statusQuery.isFetching && !hasReachedTerminalState.current,
    error: statusQuery.error,
    hasReachedTerminalState: hasReachedTerminalState.current,
  };
}
