/**
 * useRebalancing Hook
 * Handles portfolio rebalancing operations and state management
 */

import { useCallback } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import type {
  RebalanceRecommendation,
  RebalanceCalculation,
  Portfolio,
} from '../../../services/portfolio.service';

// ============================================================================
// Types
// ============================================================================

export interface RebalanceSettings {
  threshold: number;
  autoRebalance: boolean;
  frequency: 'manual' | 'weekly' | 'monthly' | 'quarterly';
  notifyOnDrift: boolean;
}

export interface RebalanceHistoryItem {
  id: string;
  portfolioId: string;
  date: string;
  tradesCount: number;
  totalVolume: number;
  driftBefore: number;
  driftAfter: number;
  status: 'completed' | 'partial' | 'failed';
  trades: RebalanceTrade[];
}

export interface RebalanceTrade {
  asset: string;
  action: 'buy' | 'sell';
  quantity: number;
  price: number;
  value: number;
}

export interface UseRebalancingOptions {
  onExecuteSuccess?: (portfolio: Portfolio) => void;
  onExecuteError?: (error: Error) => void;
}

// ============================================================================
// API Functions
// ============================================================================

const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3080';

async function getRecommendations(portfolioId: string): Promise<RebalanceRecommendation[]> {
  const response = await fetch(
    `${API_URL}/api/v1/portfolio/${portfolioId}/rebalance`,
    { credentials: 'include' }
  );

  if (!response.ok) {
    throw new Error('Failed to fetch rebalance recommendations');
  }

  const data = await response.json();
  return data.data || data;
}

async function calculateRebalance(portfolioId: string): Promise<RebalanceCalculation> {
  const response = await fetch(
    `${API_URL}/api/v1/portfolio/${portfolioId}/rebalance/calculate`,
    { credentials: 'include' }
  );

  if (!response.ok) {
    throw new Error('Failed to calculate rebalance');
  }

  const data = await response.json();
  return data.data || data;
}

async function executeRebalance(portfolioId: string): Promise<Portfolio> {
  const response = await fetch(
    `${API_URL}/api/v1/portfolio/${portfolioId}/rebalance`,
    {
      method: 'POST',
      credentials: 'include',
    }
  );

  if (!response.ok) {
    throw new Error('Failed to execute rebalance');
  }

  const data = await response.json();
  return data.data || data;
}

async function getRebalanceHistory(portfolioId: string): Promise<RebalanceHistoryItem[]> {
  const response = await fetch(
    `${API_URL}/api/v1/portfolio/${portfolioId}/rebalance/history`,
    { credentials: 'include' }
  );

  if (!response.ok) {
    throw new Error('Failed to fetch rebalance history');
  }

  const data = await response.json();
  return data.data || data;
}

async function getRebalanceSettings(portfolioId: string): Promise<RebalanceSettings> {
  const response = await fetch(
    `${API_URL}/api/v1/portfolio/${portfolioId}/rebalance/settings`,
    { credentials: 'include' }
  );

  if (!response.ok) {
    throw new Error('Failed to fetch rebalance settings');
  }

  const data = await response.json();
  return data.data || data;
}

async function updateRebalanceSettings(
  portfolioId: string,
  settings: Partial<RebalanceSettings>
): Promise<RebalanceSettings> {
  const response = await fetch(
    `${API_URL}/api/v1/portfolio/${portfolioId}/rebalance/settings`,
    {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify(settings),
    }
  );

  if (!response.ok) {
    throw new Error('Failed to update rebalance settings');
  }

  const data = await response.json();
  return data.data || data;
}

// ============================================================================
// Hook
// ============================================================================

export function useRebalancing(
  portfolioId: string,
  options: UseRebalancingOptions = {}
) {
  const queryClient = useQueryClient();

  // Fetch recommendations
  const recommendationsQuery = useQuery({
    queryKey: ['rebalance', portfolioId, 'recommendations'],
    queryFn: () => getRecommendations(portfolioId),
    enabled: !!portfolioId,
    staleTime: 60 * 1000, // 1 minute
  });

  // Fetch calculation
  const calculationQuery = useQuery({
    queryKey: ['rebalance', portfolioId, 'calculation'],
    queryFn: () => calculateRebalance(portfolioId),
    enabled: !!portfolioId,
    staleTime: 60 * 1000,
  });

  // Fetch history
  const historyQuery = useQuery({
    queryKey: ['rebalance', portfolioId, 'history'],
    queryFn: () => getRebalanceHistory(portfolioId),
    enabled: !!portfolioId,
    staleTime: 5 * 60 * 1000, // 5 minutes
  });

  // Fetch settings
  const settingsQuery = useQuery({
    queryKey: ['rebalance', portfolioId, 'settings'],
    queryFn: () => getRebalanceSettings(portfolioId),
    enabled: !!portfolioId,
    staleTime: 10 * 60 * 1000, // 10 minutes
  });

  // Execute rebalance mutation
  const executeMutation = useMutation({
    mutationFn: () => executeRebalance(portfolioId),
    onSuccess: (portfolio) => {
      // Invalidate related queries
      queryClient.invalidateQueries({ queryKey: ['portfolio', portfolioId] });
      queryClient.invalidateQueries({ queryKey: ['rebalance', portfolioId] });
      options.onExecuteSuccess?.(portfolio);
    },
    onError: (error: Error) => {
      options.onExecuteError?.(error);
    },
  });

  // Update settings mutation
  const updateSettingsMutation = useMutation({
    mutationFn: (settings: Partial<RebalanceSettings>) =>
      updateRebalanceSettings(portfolioId, settings),
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: ['rebalance', portfolioId, 'settings'],
      });
    },
  });

  // Calculate max drift from recommendations
  const maxDrift = useCallback(() => {
    if (!recommendationsQuery.data) return 0;
    return Math.max(
      ...recommendationsQuery.data.map((r) =>
        Math.abs(r.currentPercent - r.targetPercent)
      ),
      0
    );
  }, [recommendationsQuery.data]);

  // Get active recommendations (excluding holds)
  const activeRecommendations = useCallback(() => {
    if (!recommendationsQuery.data) return [];
    return recommendationsQuery.data.filter((r) => r.action !== 'hold');
  }, [recommendationsQuery.data]);

  // Check if rebalance is needed
  const needsRebalance = useCallback(
    (threshold: number = 5) => {
      return maxDrift() > threshold;
    },
    [maxDrift]
  );

  // Calculate total trade volume
  const totalTradeVolume = useCallback(() => {
    const active = activeRecommendations();
    return active.reduce((sum, r) => sum + r.amountUSD, 0);
  }, [activeRecommendations]);

  return {
    // Data
    recommendations: recommendationsQuery.data || [],
    calculation: calculationQuery.data,
    history: historyQuery.data || [],
    settings: settingsQuery.data,

    // Computed values
    maxDrift: maxDrift(),
    activeRecommendations: activeRecommendations(),
    totalTradeVolume: totalTradeVolume(),
    needsRebalance,

    // Loading states
    isLoading:
      recommendationsQuery.isLoading ||
      calculationQuery.isLoading ||
      settingsQuery.isLoading,
    isLoadingHistory: historyQuery.isLoading,
    isExecuting: executeMutation.isPending,
    isUpdatingSettings: updateSettingsMutation.isPending,

    // Error states
    error:
      recommendationsQuery.error ||
      calculationQuery.error ||
      settingsQuery.error,
    historyError: historyQuery.error,

    // Actions
    execute: executeMutation.mutate,
    executeAsync: executeMutation.mutateAsync,
    updateSettings: updateSettingsMutation.mutate,
    updateSettingsAsync: updateSettingsMutation.mutateAsync,

    // Refetch
    refetchRecommendations: recommendationsQuery.refetch,
    refetchCalculation: calculationQuery.refetch,
    refetchHistory: historyQuery.refetch,
    refetchSettings: settingsQuery.refetch,
    refetchAll: () => {
      recommendationsQuery.refetch();
      calculationQuery.refetch();
      historyQuery.refetch();
      settingsQuery.refetch();
    },
  };
}

export default useRebalancing;
