/**
 * Forecasting React Query hooks
 */
import { 
  useMutation, 
  useQuery, 
  useQueryClient, 
  UseQueryOptions, 
  UseMutationOptions,
  useInfiniteQuery,
  UseInfiniteQueryOptions,
} from '@tanstack/react-query';
import { forecastingService } from '../services/forecasting';
import {
  ForecastRequest,
  ForecastResponse,
  BatchForecastRequest,
  BatchForecastResponse,
  ListForecastsParams,
  ForecastStatisticsParams,
} from '../types/forecasting';
import { ApiError } from '../client/apiClient';

// ================================================================
// QUERY KEYS
// ================================================================

export const forecastingKeys = {
  all: ['forecasting'] as const,
  lists: () => [...forecastingKeys.all, 'list'] as const,
  list: (tenantId: string, filters?: ListForecastsParams) =>
    [...forecastingKeys.lists(), tenantId, filters] as const,
  details: () => [...forecastingKeys.all, 'detail'] as const,
  detail: (tenantId: string, forecastId: string) => 
    [...forecastingKeys.details(), tenantId, forecastId] as const,
  statistics: (tenantId: string) => 
    [...forecastingKeys.all, 'statistics', tenantId] as const,
  health: () => [...forecastingKeys.all, 'health'] as const,
} as const;

// ================================================================
// QUERIES
// ================================================================

/**
 * Get tenant forecasts with filtering and pagination
 */
export const useTenantForecasts = (
  tenantId: string,
  params?: ListForecastsParams,
  options?: Omit<UseQueryOptions<{ forecasts: ForecastResponse[]; total: number }, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<{ forecasts: ForecastResponse[]; total: number }, ApiError>({
    queryKey: forecastingKeys.list(tenantId, params),
    queryFn: () => forecastingService.getTenantForecasts(tenantId, params),
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: !!tenantId,
    ...options,
  });
};

/**
 * Get specific forecast by ID
 */
export const useForecastById = (
  tenantId: string,
  forecastId: string,
  options?: Omit<UseQueryOptions<ForecastResponse, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ForecastResponse, ApiError>({
    queryKey: forecastingKeys.detail(tenantId, forecastId),
    queryFn: () => forecastingService.getForecastById(tenantId, forecastId),
    staleTime: 5 * 60 * 1000, // 5 minutes
    enabled: !!tenantId && !!forecastId,
    ...options,
  });
};

/**
 * Get forecast statistics for tenant
 */
export const useForecastStatistics = (
  tenantId: string,
  options?: Omit<UseQueryOptions<any, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<any, ApiError>({
    queryKey: forecastingKeys.statistics(tenantId),
    queryFn: () => forecastingService.getForecastStatistics(tenantId),
    staleTime: 5 * 60 * 1000, // 5 minutes
    enabled: !!tenantId,
    ...options,
  });
};

/**
 * Health check for forecasting service
 */
export const useForecastingHealth = (
  options?: Omit<UseQueryOptions<{ status: string; service: string }, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<{ status: string; service: string }, ApiError>({
    queryKey: forecastingKeys.health(),
    queryFn: () => forecastingService.getHealthCheck(),
    staleTime: 30 * 1000, // 30 seconds
    ...options,
  });
};

// ================================================================
// INFINITE QUERIES
// ================================================================

/**
 * Infinite query for tenant forecasts (for pagination)
 */
export const useInfiniteTenantForecasts = (
  tenantId: string,
  baseParams?: Omit<ListForecastsParams, 'skip' | 'limit'>,
  options?: Omit<UseInfiniteQueryOptions<{ forecasts: ForecastResponse[]; total: number }, ApiError>, 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam' | 'select'>
) => {
  const limit = 20;

  return useInfiniteQuery<{ forecasts: ForecastResponse[]; total: number }, ApiError>({
    queryKey: [...forecastingKeys.list(tenantId, baseParams), 'infinite'],
    queryFn: ({ pageParam = 0 }) => {
      const params: ListForecastsParams = {
        ...baseParams,
        skip: pageParam as number,
        limit,
      };
      return forecastingService.getTenantForecasts(tenantId, params);
    },
    initialPageParam: 0,
    getNextPageParam: (lastPage, allPages) => {
      const totalFetched = allPages.reduce((sum, page) => sum + page.forecasts.length, 0);
      return lastPage.forecasts.length === limit ? totalFetched : undefined;
    },
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: !!tenantId,
    ...options,
  });
};

// ================================================================
// MUTATIONS
// ================================================================

/**
 * Create single forecast mutation
 */
export const useCreateSingleForecast = (
  options?: UseMutationOptions<
    ForecastResponse,
    ApiError,
    { tenantId: string; request: ForecastRequest }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    ForecastResponse,
    ApiError,
    { tenantId: string; request: ForecastRequest }
  >({
    mutationFn: ({ tenantId, request }) =>
      forecastingService.createSingleForecast(tenantId, request),
    onSuccess: (data, variables) => {
      // Invalidate and refetch forecasts list
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.lists(),
      });
      
      // Update the specific forecast cache
      queryClient.setQueryData(
        forecastingKeys.detail(variables.tenantId, data.id),
        {
          ...data,
          enhanced_features: true,
          repository_integration: true,
        } as ForecastByIdResponse
      );
      
      // Update statistics
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.statistics(variables.tenantId),
      });
    },
    ...options,
  });
};

/**
 * Create batch forecast mutation
 */
export const useCreateBatchForecast = (
  options?: UseMutationOptions<
    BatchForecastResponse,
    ApiError,
    { tenantId: string; request: BatchForecastRequest }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    BatchForecastResponse,
    ApiError,
    { tenantId: string; request: BatchForecastRequest }
  >({
    mutationFn: ({ tenantId, request }) =>
      forecastingService.createBatchForecast(tenantId, request),
    onSuccess: (data, variables) => {
      // Invalidate forecasts list
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.lists(),
      });
      
      // Cache individual forecasts if available
      if (data.forecasts) {
        data.forecasts.forEach((forecast) => {
          queryClient.setQueryData(
            forecastingKeys.detail(variables.tenantId, forecast.id),
            forecast
          );
        });
      }
      
      // Update statistics
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.statistics(variables.tenantId),
      });
    },
    ...options,
  });
};

/**
 * Delete forecast mutation
 */
export const useDeleteForecast = (
  options?: UseMutationOptions<
    { message: string },
    ApiError,
    { tenantId: string; forecastId: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    { message: string },
    ApiError,
    { tenantId: string; forecastId: string }
  >({
    mutationFn: ({ tenantId, forecastId }) =>
      forecastingService.deleteForecast(tenantId, forecastId),
    onSuccess: (data, variables) => {
      // Remove from cache
      queryClient.removeQueries({
        queryKey: forecastingKeys.detail(variables.tenantId, variables.forecastId),
      });
      
      // Invalidate lists to refresh
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.lists(),
      });
      
      // Update statistics
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.statistics(variables.tenantId),
      });
    },
    ...options,
  });
};

// ================================================================
// UTILITY FUNCTIONS
// ================================================================

/**
 * Prefetch forecast by ID
 */
export const usePrefetchForecast = () => {
  const queryClient = useQueryClient();

  return (tenantId: string, forecastId: string) => {
    queryClient.prefetchQuery({
      queryKey: forecastingKeys.detail(tenantId, forecastId),
      queryFn: () => forecastingService.getForecastById(tenantId, forecastId),
      staleTime: 5 * 60 * 1000, // 5 minutes
    });
  };
};

/**
 * Invalidate all forecasting queries for a tenant
 */
export const useInvalidateForecasting = () => {
  const queryClient = useQueryClient();

  return (tenantId?: string) => {
    if (tenantId) {
      // Invalidate specific tenant queries
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.list(tenantId),
      });
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.statistics(tenantId),
      });
    } else {
      // Invalidate all forecasting queries
      queryClient.invalidateQueries({
        queryKey: forecastingKeys.all,
      });
    }
  };
};