/**
 * Portfolio Store
 * Zustand store for portfolio management with real-time updates
 */

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import {
  getUserPortfolios,
  getPortfolio,
  getPortfolioStats,
  getRebalanceRecommendations,
  executeRebalance,
  updateAllocations,
  getUserGoals,
  createGoal,
  deleteGoal,
  type Portfolio,
  type PortfolioStats,
  type RebalanceRecommendation,
  type PortfolioGoal,
  type CreateGoalInput,
} from '../services/portfolio.service';
import { portfolioWS, type PortfolioUpdate } from '../services/websocket.service';

// ============================================================================
// State Interface
// ============================================================================

interface PortfolioState {
  // Portfolio data
  portfolios: Portfolio[];
  selectedPortfolio: Portfolio | null;
  stats: PortfolioStats | null;
  recommendations: RebalanceRecommendation[];
  goals: PortfolioGoal[];

  // Loading states
  loading: boolean;
  loadingStats: boolean;
  loadingRecommendations: boolean;
  loadingGoals: boolean;
  isRebalancing: boolean;

  // Error state
  error: string | null;

  // WebSocket state
  wsConnected: boolean;
  lastUpdate: string | null;

  // Actions
  fetchPortfolios: () => Promise<void>;
  selectPortfolio: (portfolio: Portfolio) => Promise<void>;
  selectPortfolioById: (portfolioId: string) => Promise<void>;
  refreshStats: () => Promise<void>;
  refreshRecommendations: () => Promise<void>;
  executeRebalance: () => Promise<void>;
  updateAllocations: (allocations: { asset: string; targetPercent: number }[]) => Promise<void>;

  // Goal actions
  fetchGoals: () => Promise<void>;
  createGoal: (input: CreateGoalInput) => Promise<void>;
  deleteGoal: (goalId: string) => Promise<void>;

  // WebSocket actions
  connectWebSocket: () => void;
  disconnectWebSocket: () => void;
  handlePortfolioUpdate: (update: PortfolioUpdate) => void;

  // Utility actions
  clearError: () => void;
  reset: () => void;
}

// ============================================================================
// Initial State
// ============================================================================

const initialState = {
  portfolios: [],
  selectedPortfolio: null,
  stats: null,
  recommendations: [],
  goals: [],
  loading: false,
  loadingStats: false,
  loadingRecommendations: false,
  loadingGoals: false,
  isRebalancing: false,
  error: null,
  wsConnected: false,
  lastUpdate: null,
};

// ============================================================================
// Store
// ============================================================================

export const usePortfolioStore = create<PortfolioState>()(
  devtools(
    (set, get) => ({
      ...initialState,

      // ========================================================================
      // Portfolio Actions
      // ========================================================================

      fetchPortfolios: async () => {
        set({ loading: true, error: null });

        try {
          const [portfolios, goals] = await Promise.all([
            getUserPortfolios(),
            getUserGoals(),
          ]);

          set({ portfolios, goals, loading: false });

          // Auto-select first portfolio if none selected
          if (portfolios.length > 0 && !get().selectedPortfolio) {
            await get().selectPortfolio(portfolios[0]);
          }
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Error loading portfolios';
          set({ error: message, loading: false });
        }
      },

      selectPortfolio: async (portfolio: Portfolio) => {
        set({ selectedPortfolio: portfolio, loadingStats: true, loadingRecommendations: true });

        // Disconnect from previous portfolio WebSocket
        const prevPortfolio = get().selectedPortfolio;
        if (prevPortfolio && prevPortfolio.id !== portfolio.id) {
          portfolioWS.send('portfolio:unsubscribe', { portfolioId: prevPortfolio.id });
        }

        // Subscribe to new portfolio WebSocket
        if (get().wsConnected) {
          portfolioWS.send('portfolio:subscribe', { portfolioId: portfolio.id });
        }

        try {
          const [stats, recommendations] = await Promise.all([
            getPortfolioStats(portfolio.id),
            getRebalanceRecommendations(portfolio.id),
          ]);

          set({
            stats,
            recommendations,
            loadingStats: false,
            loadingRecommendations: false,
          });
        } catch (error) {
          console.error('Error loading portfolio data:', error);
          set({ loadingStats: false, loadingRecommendations: false });
        }
      },

      selectPortfolioById: async (portfolioId: string) => {
        set({ loading: true, error: null });

        try {
          const portfolio = await getPortfolio(portfolioId);
          await get().selectPortfolio(portfolio);
          set({ loading: false });
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Portfolio not found';
          set({ error: message, loading: false });
        }
      },

      refreshStats: async () => {
        const { selectedPortfolio } = get();
        if (!selectedPortfolio) return;

        set({ loadingStats: true });

        try {
          const stats = await getPortfolioStats(selectedPortfolio.id);
          set({ stats, loadingStats: false });
        } catch (error) {
          console.error('Error refreshing stats:', error);
          set({ loadingStats: false });
        }
      },

      refreshRecommendations: async () => {
        const { selectedPortfolio } = get();
        if (!selectedPortfolio) return;

        set({ loadingRecommendations: true });

        try {
          const recommendations = await getRebalanceRecommendations(selectedPortfolio.id);
          set({ recommendations, loadingRecommendations: false });
        } catch (error) {
          console.error('Error refreshing recommendations:', error);
          set({ loadingRecommendations: false });
        }
      },

      executeRebalance: async () => {
        const { selectedPortfolio } = get();
        if (!selectedPortfolio) return;

        set({ isRebalancing: true, error: null });

        try {
          const updated = await executeRebalance(selectedPortfolio.id);
          set({
            selectedPortfolio: updated,
            isRebalancing: false,
          });

          // Refresh recommendations after rebalance
          await get().refreshRecommendations();
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Error executing rebalance';
          set({ error: message, isRebalancing: false });
        }
      },

      updateAllocations: async (allocations) => {
        const { selectedPortfolio } = get();
        if (!selectedPortfolio) return;

        set({ loading: true, error: null });

        try {
          const updated = await updateAllocations(selectedPortfolio.id, allocations);
          set({
            selectedPortfolio: updated,
            loading: false,
          });

          // Refresh recommendations after update
          await get().refreshRecommendations();
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Error updating allocations';
          set({ error: message, loading: false });
          throw error;
        }
      },

      // ========================================================================
      // Goal Actions
      // ========================================================================

      fetchGoals: async () => {
        set({ loadingGoals: true, error: null });

        try {
          const goals = await getUserGoals();
          set({ goals, loadingGoals: false });
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Error loading goals';
          set({ error: message, loadingGoals: false });
        }
      },

      createGoal: async (input: CreateGoalInput) => {
        set({ loadingGoals: true, error: null });

        try {
          const newGoal = await createGoal(input);
          set((state) => ({
            goals: [...state.goals, newGoal],
            loadingGoals: false,
          }));
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Error creating goal';
          set({ error: message, loadingGoals: false });
          throw error;
        }
      },

      deleteGoal: async (goalId: string) => {
        set({ error: null });

        try {
          await deleteGoal(goalId);
          set((state) => ({
            goals: state.goals.filter((g) => g.id !== goalId),
          }));
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Error deleting goal';
          set({ error: message });
          throw error;
        }
      },

      // ========================================================================
      // WebSocket Actions
      // ========================================================================

      connectWebSocket: () => {
        portfolioWS.connect();

        portfolioWS.onConnect(() => {
          set({ wsConnected: true });

          // Subscribe to selected portfolio if any
          const { selectedPortfolio } = get();
          if (selectedPortfolio) {
            portfolioWS.send('portfolio:subscribe', { portfolioId: selectedPortfolio.id });
          }
        });

        portfolioWS.onDisconnect(() => {
          set({ wsConnected: false });
        });

        // Handle portfolio updates
        portfolioWS.subscribe('portfolio:update', (data) => {
          get().handlePortfolioUpdate(data as PortfolioUpdate);
        });
      },

      disconnectWebSocket: () => {
        const { selectedPortfolio } = get();
        if (selectedPortfolio) {
          portfolioWS.send('portfolio:unsubscribe', { portfolioId: selectedPortfolio.id });
        }
        portfolioWS.disconnect();
        set({ wsConnected: false });
      },

      handlePortfolioUpdate: (update: PortfolioUpdate) => {
        const { selectedPortfolio } = get();

        if (selectedPortfolio && update.portfolioId === selectedPortfolio.id) {
          // Update portfolio with real-time data
          set((state) => ({
            selectedPortfolio: state.selectedPortfolio
              ? {
                  ...state.selectedPortfolio,
                  totalValue: update.totalValue,
                  unrealizedPnl: update.unrealizedPnl,
                  unrealizedPnlPercent: update.unrealizedPnlPercent,
                  allocations: state.selectedPortfolio.allocations.map((alloc) => {
                    const updated = update.allocations.find((a) => a.asset === alloc.asset);
                    if (updated) {
                      return {
                        ...alloc,
                        value: updated.value,
                        currentPercent: updated.currentPercent,
                        pnl: updated.pnl,
                        pnlPercent: updated.pnlPercent,
                      };
                    }
                    return alloc;
                  }),
                }
              : null,
            lastUpdate: update.timestamp,
          }));
        }
      },

      // ========================================================================
      // Utility Actions
      // ========================================================================

      clearError: () => {
        set({ error: null });
      },

      reset: () => {
        get().disconnectWebSocket();
        set(initialState);
      },
    }),
    {
      name: 'portfolio-store',
    }
  )
);

// ============================================================================
// Selectors
// ============================================================================

export const usePortfolios = () => usePortfolioStore((state) => state.portfolios);
export const useSelectedPortfolio = () => usePortfolioStore((state) => state.selectedPortfolio);
export const usePortfolioStats = () => usePortfolioStore((state) => state.stats);
export const useRecommendations = () => usePortfolioStore((state) => state.recommendations);
export const useGoals = () => usePortfolioStore((state) => state.goals);
export const usePortfolioLoading = () => usePortfolioStore((state) => state.loading);
export const usePortfolioError = () => usePortfolioStore((state) => state.error);
export const useWsConnected = () => usePortfolioStore((state) => state.wsConnected);
export const useIsRebalancing = () => usePortfolioStore((state) => state.isRebalancing);

export default usePortfolioStore;
