/**
 * Procurement React Query hooks
 * All hooks use the ProcurementService which connects to the standalone Procurement Service backend
 */
import {
  useMutation,
  useQuery,
  useQueryClient,
  UseQueryOptions,
  UseMutationOptions,
} from '@tanstack/react-query';
import { ProcurementService } from '../services/procurement-service';
import {
  // Response types
  ProcurementPlanResponse,
  ProcurementRequirementResponse,
  ProcurementDashboardData,
  ProcurementTrendsData,
  PaginatedProcurementPlans,
  GeneratePlanResponse,
  CreatePOsResult,

  // Request types
  GeneratePlanRequest,
  AutoGenerateProcurementRequest,
  AutoGenerateProcurementResponse,
  LinkRequirementToPORequest,
  UpdateDeliveryStatusRequest,

  // Query param types
  GetProcurementPlansParams,
  GetPlanRequirementsParams,
  UpdatePlanStatusParams,
} from '../types/procurement';
import { ApiError } from '../client/apiClient';

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

export const procurementKeys = {
  all: ['procurement'] as const,

  // Analytics & Dashboard
  analytics: (tenantId: string) => [...procurementKeys.all, 'analytics', tenantId] as const,
  trends: (tenantId: string, days: number) => [...procurementKeys.all, 'trends', tenantId, days] as const,

  // Plans
  plans: () => [...procurementKeys.all, 'plans'] as const,
  plansList: (params: GetProcurementPlansParams) => [...procurementKeys.plans(), 'list', params] as const,
  plan: (tenantId: string, planId: string) => [...procurementKeys.plans(), 'detail', tenantId, planId] as const,
  planByDate: (tenantId: string, date: string) => [...procurementKeys.plans(), 'by-date', tenantId, date] as const,
  currentPlan: (tenantId: string) => [...procurementKeys.plans(), 'current', tenantId] as const,

  // Requirements
  requirements: () => [...procurementKeys.all, 'requirements'] as const,
  planRequirements: (params: GetPlanRequirementsParams) =>
    [...procurementKeys.requirements(), 'plan', params] as const,
  criticalRequirements: (tenantId: string) =>
    [...procurementKeys.requirements(), 'critical', tenantId] as const,
} as const;

// ===================================================================
// ANALYTICS & DASHBOARD QUERIES
// ===================================================================

/**
 * Get procurement analytics dashboard data
 */
export const useProcurementDashboard = (
  tenantId: string,
  options?: Omit<UseQueryOptions<ProcurementDashboardData, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementDashboardData, ApiError>({
    queryKey: procurementKeys.analytics(tenantId),
    queryFn: () => ProcurementService.getProcurementAnalytics(tenantId),
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: !!tenantId,
    ...options,
  });
};

/**
 * Get procurement time-series trends for charts
 */
export const useProcurementTrends = (
  tenantId: string,
  days: number = 7,
  options?: Omit<UseQueryOptions<ProcurementTrendsData, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementTrendsData, ApiError>({
    queryKey: procurementKeys.trends(tenantId, days),
    queryFn: () => ProcurementService.getProcurementTrends(tenantId, days),
    staleTime: 5 * 60 * 1000, // 5 minutes
    enabled: !!tenantId,
    ...options,
  });
};

// ===================================================================
// PROCUREMENT PLAN QUERIES
// ===================================================================

/**
 * Get list of procurement plans with pagination and filtering
 */
export const useProcurementPlans = (
  params: GetProcurementPlansParams,
  options?: Omit<UseQueryOptions<PaginatedProcurementPlans, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<PaginatedProcurementPlans, ApiError>({
    queryKey: procurementKeys.plansList(params),
    queryFn: () => ProcurementService.getProcurementPlans(params),
    staleTime: 5 * 60 * 1000, // 5 minutes
    enabled: !!params.tenant_id,
    ...options,
  });
};

/**
 * Get a single procurement plan by ID
 */
export const useProcurementPlan = (
  tenantId: string,
  planId: string,
  options?: Omit<UseQueryOptions<ProcurementPlanResponse | null, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementPlanResponse | null, ApiError>({
    queryKey: procurementKeys.plan(tenantId, planId),
    queryFn: () => ProcurementService.getProcurementPlanById(tenantId, planId),
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: !!tenantId && !!planId,
    ...options,
  });
};

/**
 * Get procurement plan for a specific date
 */
export const useProcurementPlanByDate = (
  tenantId: string,
  planDate: string,
  options?: Omit<UseQueryOptions<ProcurementPlanResponse | null, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementPlanResponse | null, ApiError>({
    queryKey: procurementKeys.planByDate(tenantId, planDate),
    queryFn: () => ProcurementService.getProcurementPlanByDate(tenantId, planDate),
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: !!tenantId && !!planDate,
    ...options,
  });
};

/**
 * Get the current day's procurement plan
 */
export const useCurrentProcurementPlan = (
  tenantId: string,
  options?: Omit<UseQueryOptions<ProcurementPlanResponse | null, ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementPlanResponse | null, ApiError>({
    queryKey: procurementKeys.currentPlan(tenantId),
    queryFn: () => ProcurementService.getCurrentProcurementPlan(tenantId),
    staleTime: 1 * 60 * 1000, // 1 minute
    enabled: !!tenantId,
    ...options,
  });
};

// ===================================================================
// PROCUREMENT REQUIREMENTS QUERIES
// ===================================================================

/**
 * Get requirements for a specific procurement plan
 */
export const usePlanRequirements = (
  params: GetPlanRequirementsParams,
  options?: Omit<UseQueryOptions<ProcurementRequirementResponse[], ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementRequirementResponse[], ApiError>({
    queryKey: procurementKeys.planRequirements(params),
    queryFn: () => ProcurementService.getPlanRequirements(params),
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: !!params.tenant_id && !!params.plan_id,
    ...options,
  });
};

/**
 * Get critical requirements across all plans
 */
export const useCriticalRequirements = (
  tenantId: string,
  options?: Omit<UseQueryOptions<ProcurementRequirementResponse[], ApiError>, 'queryKey' | 'queryFn'>
) => {
  return useQuery<ProcurementRequirementResponse[], ApiError>({
    queryKey: procurementKeys.criticalRequirements(tenantId),
    queryFn: () => ProcurementService.getCriticalRequirements(tenantId),
    staleTime: 1 * 60 * 1000, // 1 minute
    enabled: !!tenantId,
    ...options,
  });
};

// ===================================================================
// PROCUREMENT PLAN MUTATIONS
// ===================================================================

/**
 * Generate a new procurement plan (manual/UI-driven)
 */
export const useGenerateProcurementPlan = (
  options?: UseMutationOptions<GeneratePlanResponse, ApiError, { tenantId: string; request: GeneratePlanRequest }>
) => {
  const queryClient = useQueryClient();

  return useMutation<GeneratePlanResponse, ApiError, { tenantId: string; request: GeneratePlanRequest }>({
    mutationFn: ({ tenantId, request }) => ProcurementService.generateProcurementPlan(tenantId, request),
    onSuccess: (data, variables) => {
      // Invalidate all procurement queries for this tenant
      queryClient.invalidateQueries({
        queryKey: procurementKeys.all,
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });

      // If plan was generated successfully, cache it
      if (data.success && data.plan) {
        queryClient.setQueryData(procurementKeys.plan(variables.tenantId, data.plan.id), data.plan);
      }
    },
    ...options,
  });
};

/**
 * Auto-generate procurement plan from forecast data (Orchestrator integration)
 */
export const useAutoGenerateProcurement = (
  options?: UseMutationOptions<
    AutoGenerateProcurementResponse,
    ApiError,
    { tenantId: string; request: AutoGenerateProcurementRequest }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    AutoGenerateProcurementResponse,
    ApiError,
    { tenantId: string; request: AutoGenerateProcurementRequest }
  >({
    mutationFn: ({ tenantId, request }) => ProcurementService.autoGenerateProcurement(tenantId, request),
    onSuccess: (data, variables) => {
      // Invalidate all procurement queries
      queryClient.invalidateQueries({
        queryKey: procurementKeys.all,
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });

      // If plan was created successfully, cache it
      if (data.success && data.plan_id) {
        queryClient.invalidateQueries({
          queryKey: procurementKeys.currentPlan(variables.tenantId),
        });
      }
    },
    ...options,
  });
};

/**
 * Update procurement plan status
 */
export const useUpdateProcurementPlanStatus = (
  options?: UseMutationOptions<ProcurementPlanResponse, ApiError, UpdatePlanStatusParams>
) => {
  const queryClient = useQueryClient();

  return useMutation<ProcurementPlanResponse, ApiError, UpdatePlanStatusParams>({
    mutationFn: (params) => ProcurementService.updateProcurementPlanStatus(params),
    onSuccess: (data, variables) => {
      // Update the specific plan in cache
      queryClient.setQueryData(procurementKeys.plan(variables.tenant_id, variables.plan_id), data);

      // Invalidate plans list
      queryClient.invalidateQueries({
        queryKey: procurementKeys.plans(),
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenant_id);
        },
      });
    },
    ...options,
  });
};

/**
 * Recalculate an existing procurement plan
 */
export const useRecalculateProcurementPlan = (
  options?: UseMutationOptions<GeneratePlanResponse, ApiError, { tenantId: string; planId: string }>
) => {
  const queryClient = useQueryClient();

  return useMutation<GeneratePlanResponse, ApiError, { tenantId: string; planId: string }>({
    mutationFn: ({ tenantId, planId }) => ProcurementService.recalculateProcurementPlan(tenantId, planId),
    onSuccess: (data, variables) => {
      if (data.plan) {
        // Update the specific plan in cache
        queryClient.setQueryData(procurementKeys.plan(variables.tenantId, variables.planId), data.plan);
      }

      // Invalidate plans list and dashboard
      queryClient.invalidateQueries({
        queryKey: procurementKeys.all,
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });
    },
    ...options,
  });
};

/**
 * Approve a procurement plan
 */
export const useApproveProcurementPlan = (
  options?: UseMutationOptions<
    ProcurementPlanResponse,
    ApiError,
    { tenantId: string; planId: string; approval_notes?: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    ProcurementPlanResponse,
    ApiError,
    { tenantId: string; planId: string; approval_notes?: string }
  >({
    mutationFn: ({ tenantId, planId, approval_notes }) =>
      ProcurementService.approveProcurementPlan(tenantId, planId, { approval_notes }),
    onSuccess: (data, variables) => {
      // Update the specific plan in cache
      queryClient.setQueryData(procurementKeys.plan(variables.tenantId, variables.planId), data);

      // Invalidate plans list and dashboard
      queryClient.invalidateQueries({
        queryKey: procurementKeys.all,
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });
    },
    ...options,
  });
};

/**
 * Reject a procurement plan
 */
export const useRejectProcurementPlan = (
  options?: UseMutationOptions<
    ProcurementPlanResponse,
    ApiError,
    { tenantId: string; planId: string; rejection_notes?: string }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    ProcurementPlanResponse,
    ApiError,
    { tenantId: string; planId: string; rejection_notes?: string }
  >({
    mutationFn: ({ tenantId, planId, rejection_notes }) =>
      ProcurementService.rejectProcurementPlan(tenantId, planId, { rejection_notes }),
    onSuccess: (data, variables) => {
      // Update the specific plan in cache
      queryClient.setQueryData(procurementKeys.plan(variables.tenantId, variables.planId), data);

      // Invalidate plans list and dashboard
      queryClient.invalidateQueries({
        queryKey: procurementKeys.all,
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });
    },
    ...options,
  });
};

// ===================================================================
// PURCHASE ORDER MUTATIONS
// ===================================================================

/**
 * Create purchase orders from procurement plan
 */
export const useCreatePurchaseOrdersFromPlan = (
  options?: UseMutationOptions<CreatePOsResult, ApiError, { tenantId: string; planId: string; autoApprove?: boolean }>
) => {
  const queryClient = useQueryClient();

  return useMutation<CreatePOsResult, ApiError, { tenantId: string; planId: string; autoApprove?: boolean }>({
    mutationFn: ({ tenantId, planId, autoApprove = false }) =>
      ProcurementService.createPurchaseOrdersFromPlan(tenantId, planId, autoApprove),
    onSuccess: (data, variables) => {
      // Invalidate procurement plan to refresh requirements status
      queryClient.invalidateQueries({
        queryKey: procurementKeys.plan(variables.tenantId, variables.planId),
      });

      // Invalidate plan requirements
      queryClient.invalidateQueries({
        queryKey: procurementKeys.requirements(),
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.planId);
        },
      });
    },
    ...options,
  });
};

/**
 * Link a procurement requirement to a purchase order
 */
export const useLinkRequirementToPurchaseOrder = (
  options?: UseMutationOptions<
    { success: boolean; message: string; requirement_id: string; purchase_order_id: string },
    ApiError,
    { tenantId: string; requirementId: string; request: LinkRequirementToPORequest }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    { success: boolean; message: string; requirement_id: string; purchase_order_id: string },
    ApiError,
    { tenantId: string; requirementId: string; request: LinkRequirementToPORequest }
  >({
    mutationFn: ({ tenantId, requirementId, request }) =>
      ProcurementService.linkRequirementToPurchaseOrder(tenantId, requirementId, request),
    onSuccess: (data, variables) => {
      // Invalidate procurement data to refresh requirements
      queryClient.invalidateQueries({
        queryKey: procurementKeys.requirements(),
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });
    },
    ...options,
  });
};

/**
 * Update delivery status for a requirement
 */
export const useUpdateRequirementDeliveryStatus = (
  options?: UseMutationOptions<
    { success: boolean; message: string; requirement_id: string; delivery_status: string },
    ApiError,
    { tenantId: string; requirementId: string; request: UpdateDeliveryStatusRequest }
  >
) => {
  const queryClient = useQueryClient();

  return useMutation<
    { success: boolean; message: string; requirement_id: string; delivery_status: string },
    ApiError,
    { tenantId: string; requirementId: string; request: UpdateDeliveryStatusRequest }
  >({
    mutationFn: ({ tenantId, requirementId, request }) =>
      ProcurementService.updateRequirementDeliveryStatus(tenantId, requirementId, request),
    onSuccess: (data, variables) => {
      // Invalidate procurement data to refresh requirements
      queryClient.invalidateQueries({
        queryKey: procurementKeys.requirements(),
        predicate: (query) => {
          return JSON.stringify(query.queryKey).includes(variables.tenantId);
        },
      });
    },
    ...options,
  });
};
