/**
 * Alert Processor React Query hooks
 * Provides data fetching, caching, and state management for alert processing operations
 */

import { useMutation, useQuery, useQueryClient, UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
import { alertProcessorService } from '../services/alert_processor';
import { ApiError } from '../client/apiClient';
import type {
  AlertResponse,
  AlertUpdateRequest,
  AlertQueryParams,
  AlertDashboardData,
  NotificationSettings,
  ChannelRoutingConfig,
  WebhookConfig,
  AlertProcessingStatus,
  ProcessingMetrics,
  PaginatedResponse,
} from '../types/alert_processor';

// Query Keys Factory
export const alertProcessorKeys = {
  all: ['alert-processor'] as const,
  alerts: {
    all: () => [...alertProcessorKeys.all, 'alerts'] as const,
    lists: () => [...alertProcessorKeys.alerts.all(), 'list'] as const,
    list: (tenantId: string, params?: AlertQueryParams) => 
      [...alertProcessorKeys.alerts.lists(), tenantId, params] as const,
    details: () => [...alertProcessorKeys.alerts.all(), 'detail'] as const,
    detail: (tenantId: string, alertId: string) => 
      [...alertProcessorKeys.alerts.details(), tenantId, alertId] as const,
    dashboard: (tenantId: string) => 
      [...alertProcessorKeys.alerts.all(), 'dashboard', tenantId] as const,
    processingStatus: (tenantId: string, alertId: string) => 
      [...alertProcessorKeys.alerts.all(), 'processing-status', tenantId, alertId] as const,
  },
  notifications: {
    all: () => [...alertProcessorKeys.all, 'notifications'] as const,
    settings: (tenantId: string) => 
      [...alertProcessorKeys.notifications.all(), 'settings', tenantId] as const,
    routing: () => 
      [...alertProcessorKeys.notifications.all(), 'routing-config'] as const,
  },
  webhooks: {
    all: () => [...alertProcessorKeys.all, 'webhooks'] as const,
    list: (tenantId: string) => 
      [...alertProcessorKeys.webhooks.all(), tenantId] as const,
  },
  metrics: {
    all: () => [...alertProcessorKeys.all, 'metrics'] as const,
    processing: (tenantId: string) => 
      [...alertProcessorKeys.metrics.all(), 'processing', tenantId] as const,
  },
} as const;

// Alert Queries
export const useAlerts = (
  tenantId: string,
  queryParams?: AlertQueryParams,
  options?: Omit<UseQueryOptions<PaginatedResponse<AlertResponse>, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<PaginatedResponse<AlertResponse>, ApiError>({
    queryKey: alertProcessorKeys.alerts.list(tenantId, queryParams),
    queryFn: () => alertProcessorService.getAlerts(tenantId, queryParams),
    enabled: !!tenantId,
    staleTime: 30 * 1000, // 30 seconds
    ...options,
  });
};

export const useAlert = (
  tenantId: string,
  alertId: string,
  options?: Omit<UseQueryOptions<AlertResponse, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<AlertResponse, ApiError>({
    queryKey: alertProcessorKeys.alerts.detail(tenantId, alertId),
    queryFn: () => alertProcessorService.getAlert(tenantId, alertId),
    enabled: !!tenantId && !!alertId,
    staleTime: 1 * 60 * 1000, // 1 minute
    ...options,
  });
};

export const useAlertDashboardData = (
  tenantId: string,
  options?: Omit<UseQueryOptions<AlertDashboardData, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<AlertDashboardData, ApiError>({
    queryKey: alertProcessorKeys.alerts.dashboard(tenantId),
    queryFn: () => alertProcessorService.getDashboardData(tenantId),
    enabled: !!tenantId,
    staleTime: 30 * 1000, // 30 seconds
    refetchInterval: 1 * 60 * 1000, // Refresh every minute
    ...options,
  });
};

export const useAlertProcessingStatus = (
  tenantId: string,
  alertId: string,
  options?: Omit<UseQueryOptions<AlertProcessingStatus, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<AlertProcessingStatus, ApiError>({
    queryKey: alertProcessorKeys.alerts.processingStatus(tenantId, alertId),
    queryFn: () => alertProcessorService.getProcessingStatus(tenantId, alertId),
    enabled: !!tenantId && !!alertId,
    staleTime: 10 * 1000, // 10 seconds
    refetchInterval: 30 * 1000, // Poll every 30 seconds
    ...options,
  });
};

// Notification Queries
export const useNotificationSettings = (
  tenantId: string,
  options?: Omit<UseQueryOptions<NotificationSettings, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<NotificationSettings, ApiError>({
    queryKey: alertProcessorKeys.notifications.settings(tenantId),
    queryFn: () => alertProcessorService.getNotificationSettings(tenantId),
    enabled: !!tenantId,
    staleTime: 5 * 60 * 1000, // 5 minutes
    ...options,
  });
};

export const useChannelRoutingConfig = (
  options?: Omit<UseQueryOptions<ChannelRoutingConfig, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ChannelRoutingConfig, ApiError>({
    queryKey: alertProcessorKeys.notifications.routing(),
    queryFn: () => alertProcessorService.getChannelRoutingConfig(),
    staleTime: 10 * 60 * 1000, // 10 minutes
    ...options,
  });
};

// Webhook Queries
export const useWebhooks = (
  tenantId: string,
  options?: Omit<UseQueryOptions<WebhookConfig[], ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<WebhookConfig[], ApiError>({
    queryKey: alertProcessorKeys.webhooks.list(tenantId),
    queryFn: () => alertProcessorService.getWebhooks(tenantId),
    enabled: !!tenantId,
    staleTime: 2 * 60 * 1000, // 2 minutes
    ...options,
  });
};

// Metrics Queries
export const useProcessingMetrics = (
  tenantId: string,
  options?: Omit<UseQueryOptions<ProcessingMetrics, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcessingMetrics, ApiError>({
    queryKey: alertProcessorKeys.metrics.processing(tenantId),
    queryFn: () => alertProcessorService.getProcessingMetrics(tenantId),
    enabled: !!tenantId,
    staleTime: 1 * 60 * 1000, // 1 minute
    ...options,
  });
};

// Alert Mutations
export const useUpdateAlert = (
  options?: UseMutationOptions<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string; updateData: AlertUpdateRequest }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string; updateData: AlertUpdateRequest }
  >({
    mutationFn: ({ tenantId, alertId, updateData }) =>
      alertProcessorService.updateAlert(tenantId, alertId, updateData),
    onSuccess: (data, { tenantId, alertId }) => {
      // Update the alert in cache
      queryClient.setQueryData(
        alertProcessorKeys.alerts.detail(tenantId, alertId),
        data
      );
      
      // Invalidate alerts list to reflect the change
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.lists()
      });
      
      // Invalidate dashboard data
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.dashboard(tenantId)
      });
    },
    ...options,
  });
};

export const useDismissAlert = (
  options?: UseMutationOptions<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string }
  >({
    mutationFn: ({ tenantId, alertId }) =>
      alertProcessorService.dismissAlert(tenantId, alertId),
    onSuccess: (data, { tenantId, alertId }) => {
      // Update the alert in cache
      queryClient.setQueryData(
        alertProcessorKeys.alerts.detail(tenantId, alertId),
        data
      );
      
      // Invalidate related queries
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.lists()
      });
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.dashboard(tenantId)
      });
    },
    ...options,
  });
};

export const useAcknowledgeAlert = (
  options?: UseMutationOptions<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string; notes?: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string; notes?: string }
  >({
    mutationFn: ({ tenantId, alertId, notes }) =>
      alertProcessorService.acknowledgeAlert(tenantId, alertId, notes),
    onSuccess: (data, { tenantId, alertId }) => {
      // Update the alert in cache
      queryClient.setQueryData(
        alertProcessorKeys.alerts.detail(tenantId, alertId),
        data
      );
      
      // Invalidate related queries
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.lists()
      });
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.dashboard(tenantId)
      });
    },
    ...options,
  });
};

export const useResolveAlert = (
  options?: UseMutationOptions<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string; notes?: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    AlertResponse,
    ApiError,
    { tenantId: string; alertId: string; notes?: string }
  >({
    mutationFn: ({ tenantId, alertId, notes }) =>
      alertProcessorService.resolveAlert(tenantId, alertId, notes),
    onSuccess: (data, { tenantId, alertId }) => {
      // Update the alert in cache
      queryClient.setQueryData(
        alertProcessorKeys.alerts.detail(tenantId, alertId),
        data
      );
      
      // Invalidate related queries
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.lists()
      });
      queryClient.invalidateQueries({
        queryKey: alertProcessorKeys.alerts.dashboard(tenantId)
      });
    },
    ...options,
  });
};

// Notification Settings Mutations
export const useUpdateNotificationSettings = (
  options?: UseMutationOptions<
    NotificationSettings,
    ApiError,
    { tenantId: string; settings: Partial<NotificationSettings> }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    NotificationSettings,
    ApiError,
    { tenantId: string; settings: Partial<NotificationSettings> }
  >({
    mutationFn: ({ tenantId, settings }) =>
      alertProcessorService.updateNotificationSettings(tenantId, settings),
    onSuccess: (data, { tenantId }) => {
      // Update settings in cache
      queryClient.setQueryData(
        alertProcessorKeys.notifications.settings(tenantId),
        data
      );
    },
    ...options,
  });
};

// Webhook Mutations
export const useCreateWebhook = (
  options?: UseMutationOptions<
    WebhookConfig,
    ApiError,
    { tenantId: string; webhook: Omit<WebhookConfig, 'tenant_id'> }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    WebhookConfig,
    ApiError,
    { tenantId: string; webhook: Omit<WebhookConfig, 'tenant_id'> }
  >({
    mutationFn: ({ tenantId, webhook }) =>
      alertProcessorService.createWebhook(tenantId, webhook),
    onSuccess: (data, { tenantId }) => {
      // Add the new webhook to the list
      queryClient.setQueryData(
        alertProcessorKeys.webhooks.list(tenantId),
        (oldData: WebhookConfig[] | undefined) => [...(oldData || []), data]
      );
    },
    ...options,
  });
};

export const useUpdateWebhook = (
  options?: UseMutationOptions<
    WebhookConfig,
    ApiError,
    { tenantId: string; webhookId: string; webhook: Partial<WebhookConfig> }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    WebhookConfig,
    ApiError,
    { tenantId: string; webhookId: string; webhook: Partial<WebhookConfig> }
  >({
    mutationFn: ({ tenantId, webhookId, webhook }) =>
      alertProcessorService.updateWebhook(tenantId, webhookId, webhook),
    onSuccess: (data, { tenantId }) => {
      // Update the webhook in the list
      queryClient.setQueryData(
        alertProcessorKeys.webhooks.list(tenantId),
        (oldData: WebhookConfig[] | undefined) =>
          oldData?.map(hook => hook.webhook_url === data.webhook_url ? data : hook) || []
      );
    },
    ...options,
  });
};

export const useDeleteWebhook = (
  options?: UseMutationOptions<
    { message: string },
    ApiError,
    { tenantId: string; webhookId: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    { message: string },
    ApiError,
    { tenantId: string; webhookId: string }
  >({
    mutationFn: ({ tenantId, webhookId }) =>
      alertProcessorService.deleteWebhook(tenantId, webhookId),
    onSuccess: (_, { tenantId, webhookId }) => {
      // Remove the webhook from the list
      queryClient.setQueryData(
        alertProcessorKeys.webhooks.list(tenantId),
        (oldData: WebhookConfig[] | undefined) =>
          oldData?.filter(hook => hook.webhook_url !== webhookId) || []
      );
    },
    ...options,
  });
};

export const useTestWebhook = (
  options?: UseMutationOptions<
    { success: boolean; message: string },
    ApiError,
    { tenantId: string; webhookId: string }
  >
) => {
  return useMutation<
    { success: boolean; message: string },
    ApiError,
    { tenantId: string; webhookId: string }
  >({
    mutationFn: ({ tenantId, webhookId }) =>
      alertProcessorService.testWebhook(tenantId, webhookId),
    ...options,
  });
};

// SSE Hook for Real-time Alert Updates
export const useAlertSSE = (
  tenantId: string,
  token?: string,
  options?: {
    onAlert?: (alert: AlertResponse) => void;
    onRecommendation?: (recommendation: AlertResponse) => void;
    onAlertUpdate?: (update: AlertResponse) => void;
    onSystemStatus?: (status: any) => void;
  }
) => {
  const queryClient = useQueryClient();

  return useQuery({
    queryKey: ['alert-sse', tenantId],
    queryFn: () => {
      return new Promise((resolve, reject) => {
        try {
          const eventSource = alertProcessorService.createSSEConnection(tenantId, token);

          eventSource.onopen = () => {
            console.log('Alert SSE connected');
          };

          eventSource.onmessage = (event) => {
            try {
              const message = JSON.parse(event.data);
              
              // Invalidate dashboard data on new alerts/updates
              queryClient.invalidateQueries({
                queryKey: alertProcessorKeys.alerts.dashboard(tenantId)
              });
              
              // Invalidate alerts list
              queryClient.invalidateQueries({
                queryKey: alertProcessorKeys.alerts.lists()
              });

              // Call appropriate callback based on message type
              switch (message.type) {
                case 'alert':
                  options?.onAlert?.(message.data);
                  break;
                case 'recommendation':
                  options?.onRecommendation?.(message.data);
                  break;
                case 'alert_update':
                  options?.onAlertUpdate?.(message.data);
                  // Update specific alert in cache
                  if (message.data.id) {
                    queryClient.setQueryData(
                      alertProcessorKeys.alerts.detail(tenantId, message.data.id),
                      message.data
                    );
                  }
                  break;
                case 'system_status':
                  options?.onSystemStatus?.(message.data);
                  break;
              }
            } catch (error) {
              console.error('Error parsing SSE message:', error);
            }
          };

          eventSource.onerror = (error) => {
            console.error('Alert SSE error:', error);
            reject(error);
          };

          // Return cleanup function
          return () => {
            eventSource.close();
          };
        } catch (error) {
          reject(error);
        }
      });
    },
    enabled: !!tenantId,
    refetchOnWindowFocus: false,
    retry: false,
    staleTime: Infinity,
  });
};

// Utility Hooks
export const useActiveAlertsCount = (tenantId: string) => {
  const { data: dashboardData } = useAlertDashboardData(tenantId);
  return dashboardData?.active_alerts?.length || 0;
};

export const useAlertsByPriority = (tenantId: string) => {
  const { data: dashboardData } = useAlertDashboardData(tenantId);
  return dashboardData?.severity_counts || {};
};

export const useUnreadAlertsCount = (tenantId: string) => {
  const { data: alerts } = useAlerts(tenantId, { 
    status: 'active',
    limit: 1000 // Get all active alerts to count unread ones
  });
  
  return alerts?.data?.filter(alert => alert.status === 'active')?.length || 0;
};