import { useState, useCallback } from 'react';
import api from '../api';

// Global request cache to prevent duplicate requests
const requestCache = new Map<string, Promise<any>>();
const cacheTimestamps = new Map<string, number>();
const CACHE_DURATION = 5000; // 5 seconds cache duration

// Generate cache key for request deduplication
function generateCacheKey(url: string, method: string, params?: Record<string, any>): string {
  const paramsString = params ? JSON.stringify(params) : '';
  return `${method.toUpperCase()}:${url}:${paramsString}`;
}

// Check if cached request is still valid
function isCacheValid(cacheKey: string): boolean {
  const timestamp = cacheTimestamps.get(cacheKey);
  if (!timestamp) return false;
  return Date.now() - timestamp < CACHE_DURATION;
}

// Generic API error handling
export function formatApiError(error: any, defaultMessage: string): string {
  if (error.response) {
    const data = error.response.data;
    
    // Handle FastAPI validation errors (detail is an array)
    if (data?.detail && Array.isArray(data.detail)) {
      return data.detail.map((err: any) => {
        if (typeof err === 'string') return err;
        if (err.msg) return `${err.loc?.join('.') || 'field'}: ${err.msg}`;
        return JSON.stringify(err);
      }).join(', ');
    }
    
    // Handle other error formats
    if (typeof data?.detail === 'string') return data.detail;
    if (typeof data?.message === 'string') return data.message;
    if (typeof data === 'string') return data;
    
    return defaultMessage;
  } else if (error.request) {
    return 'Keine Antwort vom Server erhalten';
  } else {
    return error.message || defaultMessage;
  }
}

// Type for API request options
export interface ApiRequestOptions<T> {
  url: string;
  method: 'get' | 'post' | 'put' | 'delete';
  data?: T;
  params?: Record<string, string | number | boolean>;
  additionalConfig?: Record<string, any>; // For responseType, headers, etc.
}

// Hook for making API requests with consistent error handling
export function useApiRequest<RequestData = any, ResponseData = any>() {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const request = useCallback(async ({
    url,
    method,
    data,
    params,
    additionalConfig = {}
  }: ApiRequestOptions<RequestData>): Promise<ResponseData> => {
    setIsLoading(true);
    setError(null);

    try {
      // Generate cache key for GET requests (only cache GET requests)
      const cacheKey = method === 'get' ? generateCacheKey(url, method, params) : null;
      
      // Check if we have a valid cached request for GET requests
      if (cacheKey && requestCache.has(cacheKey) && isCacheValid(cacheKey)) {
        console.log('🔧 useApiRequest: Using cached request', { url, method, cacheKey });
        setIsLoading(false);
        return await requestCache.get(cacheKey)!;
      }

      console.log('🔧 useApiRequest: Making request', { 
        url, 
        method, 
        hasData: !!data, 
        hasParams: !!params, 
        cacheKey,
        dataStructure: data ? {
          data,
          dataType: typeof data,
          dataKeys: Object.keys(data),
          dataEntries: Object.entries(data).map(([key, value]) => ({
            key,
            value,
            valueType: typeof value,
            valueIsObject: typeof value === 'object' && value !== null && !Array.isArray(value),
            valueStringified: typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)
          })),
          dataStringified: JSON.stringify(data, null, 2)
        } : null,
        fullRequestConfig: {
          url,
          method,
          data,
          params,
          ...additionalConfig
        }
      });
      
      // Create the request promise
      const requestPromise = api({
        url,
        method,
        data,
        params,
        ...additionalConfig
      }).then(response => {
        console.log('🔧 useApiRequest: Request successful', { url, status: response.status, hasData: !!response.data });
        
        // For blob responses, return the blob data directly
        if (additionalConfig.responseType === 'blob') {
          return response.data;
        }
        
        return response.data;
      });

      // Cache GET requests
      if (cacheKey) {
        requestCache.set(cacheKey, requestPromise);
        cacheTimestamps.set(cacheKey, Date.now());
        
        // Clean up old cache entries
        setTimeout(() => {
          if (requestCache.has(cacheKey) && !isCacheValid(cacheKey)) {
            requestCache.delete(cacheKey);
            cacheTimestamps.delete(cacheKey);
          }
        }, CACHE_DURATION + 1000);
      }
      
      const result = await requestPromise;
      setIsLoading(false);
      return result;
    } catch (error: any) {
      // Clear cache on error to allow retry
      const cacheKey = method === 'get' ? generateCacheKey(url, method, params) : null;
      if (cacheKey) {
        requestCache.delete(cacheKey);
        cacheTimestamps.delete(cacheKey);
      }
      
      console.log('🔧 useApiRequest: Request failed', { 
        url, 
        error: error.message, 
        status: error.response?.status,
        statusText: error.response?.statusText,
        hasResponse: !!error.response,
        hasRequest: !!error.request,
        isAborted: error.code === 'ERR_CANCELED',
        authAuthority: sessionStorage.getItem('auth_authority'),
        hasCookies: document.cookie.includes('access_token') || document.cookie.includes('refresh_token')
      });
      
      // Handle aborted requests specifically
      if (error.code === 'ERR_CANCELED' || error.message?.includes('aborted')) {
        const errorMessage = 'Request aborted';
        setError(errorMessage);
        throw new Error(errorMessage);
      }
      
      // Handle authentication errors specifically
      if (error.response?.status === 401) {
        const errorMessage = 'Not authenticated';
        setError(errorMessage);
        throw new Error(errorMessage);
      }
      
      // Handle rate limiting specifically
      if (error.response?.status === 429) {
        const errorMessage = error.response.data?.detail || error.response.data?.message || '30 per 1 minute';
        setError(errorMessage);
        throw new Error(errorMessage);
      }
      
      const errorMessage = formatApiError(error, `Fehler bei ${method.toUpperCase()} ${url}`);
      setError(errorMessage);
      throw new Error(String(errorMessage)); // Ensure it's a string
    } finally {
      setIsLoading(false);
    }
  }, []);

  // Function to clear cache manually
  const clearCache = useCallback((url?: string, method?: string) => {
    if (url && method) {
      const cacheKey = generateCacheKey(url, method);
      requestCache.delete(cacheKey);
      cacheTimestamps.delete(cacheKey);
      console.log('🔧 useApiRequest: Cleared cache for', { url, method, cacheKey });
    } else {
      requestCache.clear();
      cacheTimestamps.clear();
      console.log('🔧 useApiRequest: Cleared all cache');
    }
  }, []);

  return {
    request,
    isLoading,
    error,
    clearCache
  };
} 