/**
 * Trading Store
 * Zustand store for trading state management
 */

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import type {
  TradingState,
  Interval,
  Watchlist,
  WatchlistSymbolData,
  PaperBalance,
  PaperPosition,
  PaperTrade,
  AccountSummary,
  CreateOrderInput,
} from '../types/trading.types';
import { tradingService } from '../services/trading.service';

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

interface ExtendedTradingState extends TradingState {
  // Watchlist state
  watchlist: Watchlist | null;
  watchlistData: WatchlistSymbolData[];
  loadingWatchlist: boolean;

  // Watchlist actions
  fetchWatchlist: () => Promise<void>;
  addToWatchlist: (symbol: string) => Promise<void>;
  removeFromWatchlist: (symbol: string) => Promise<void>;
  refreshWatchlistData: () => Promise<void>;

  // Paper Trading state
  paperBalance: PaperBalance | null;
  paperPositions: PaperPosition[];
  paperTrades: PaperTrade[];
  paperPortfolio: AccountSummary | null;
  loadingPaperBalance: boolean;
  loadingPaperPositions: boolean;
  loadingPaperTrades: boolean;

  // Paper Trading actions
  fetchPaperBalance: () => Promise<void>;
  fetchPaperPositions: () => Promise<void>;
  fetchPaperTrades: () => Promise<void>;
  fetchPaperPortfolio: () => Promise<void>;
  createOrder: (orderData: CreateOrderInput) => Promise<void>;
  closePosition: (positionId: string) => Promise<void>;
  initializePaperAccount: () => Promise<void>;
  resetPaperAccount: () => Promise<void>;
}

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

const initialState = {
  selectedSymbol: 'BTCUSDT',
  timeframe: '1h' as Interval,
  klines: [],
  currentTicker: null,
  orderBook: null,
  loadingKlines: false,
  loadingTicker: false,
  loadingOrderBook: false,
  error: null,

  // Watchlist initial state
  watchlist: null,
  watchlistData: [],
  loadingWatchlist: false,

  // Paper Trading initial state
  paperBalance: null,
  paperPositions: [],
  paperTrades: [],
  paperPortfolio: null,
  loadingPaperBalance: false,
  loadingPaperPositions: false,
  loadingPaperTrades: false,
};

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

export const useTradingStore = create<ExtendedTradingState>()(
  devtools(
    (set, get) => ({
      ...initialState,

      // Set selected symbol
      setSymbol: (symbol: string) => {
        set({ selectedSymbol: symbol, error: null });
        // Auto-fetch data for new symbol
        get().fetchKlines(symbol);
        get().fetchTicker(symbol);
      },

      // Set timeframe
      setTimeframe: (timeframe: Interval) => {
        set({ timeframe, error: null });
        // Auto-fetch data with new timeframe
        get().fetchKlines(undefined, timeframe);
      },

      // Fetch klines (candlestick data)
      fetchKlines: async (symbol?: string, interval?: Interval, limit?: number) => {
        const state = get();
        const targetSymbol = symbol || state.selectedSymbol;
        const targetInterval = interval || state.timeframe;
        const targetLimit = limit || 500;

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

        try {
          const klines = await tradingService.getKlines(targetSymbol, targetInterval, targetLimit);
          set({ klines, loadingKlines: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch klines';
          set({ error: errorMessage, loadingKlines: false, klines: [] });
          console.error('Error fetching klines:', error);
        }
      },

      // Fetch ticker data
      fetchTicker: async (symbol?: string) => {
        const state = get();
        const targetSymbol = symbol || state.selectedSymbol;

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

        try {
          const ticker = await tradingService.getTicker(targetSymbol);
          set({ currentTicker: ticker, loadingTicker: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch ticker';
          set({ error: errorMessage, loadingTicker: false, currentTicker: null });
          console.error('Error fetching ticker:', error);
        }
      },

      // Fetch order book
      fetchOrderBook: async (symbol?: string, limit?: number) => {
        const state = get();
        const targetSymbol = symbol || state.selectedSymbol;
        const targetLimit = limit || 20;

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

        try {
          const orderBook = await tradingService.getOrderBook(targetSymbol, targetLimit);
          set({ orderBook, loadingOrderBook: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch order book';
          set({ error: errorMessage, loadingOrderBook: false, orderBook: null });
          console.error('Error fetching order book:', error);
        }
      },

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

      // ========================================================================
      // Watchlist Actions
      // ========================================================================

      // Fetch watchlist (default or user's)
      fetchWatchlist: async () => {
        set({ loadingWatchlist: true, error: null });

        try {
          // Try to get default watchlist (works for both auth and non-auth users)
          const watchlist = await tradingService.getDefaultWatchlist();
          set({ watchlist, loadingWatchlist: false });

          // Fetch prices for watchlist symbols
          if (watchlist.items.length > 0) {
            get().refreshWatchlistData();
          }
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch watchlist';
          set({ error: errorMessage, loadingWatchlist: false, watchlist: null });
          console.error('Error fetching watchlist:', error);
        }
      },

      // Add symbol to watchlist
      addToWatchlist: async (symbol: string) => {
        const state = get();
        if (!state.watchlist) {
          set({ error: 'No watchlist loaded' });
          return;
        }

        set({ error: null });

        try {
          await tradingService.addSymbolToWatchlist(state.watchlist.id, symbol);
          // Refresh watchlist to get updated data
          await get().fetchWatchlist();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to add symbol';
          set({ error: errorMessage });
          console.error('Error adding symbol to watchlist:', error);
        }
      },

      // Remove symbol from watchlist
      removeFromWatchlist: async (symbol: string) => {
        const state = get();
        if (!state.watchlist) {
          set({ error: 'No watchlist loaded' });
          return;
        }

        set({ error: null });

        try {
          await tradingService.removeSymbolFromWatchlist(state.watchlist.id, symbol);
          // Refresh watchlist to get updated data
          await get().fetchWatchlist();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to remove symbol';
          set({ error: errorMessage });
          console.error('Error removing symbol from watchlist:', error);
        }
      },

      // Refresh watchlist data (prices)
      refreshWatchlistData: async () => {
        const state = get();
        if (!state.watchlist || state.watchlist.items.length === 0) {
          return;
        }

        try {
          const symbols = state.watchlist.items.map(item => item.symbol);
          const data = await tradingService.getWatchlistData(symbols);
          set({ watchlistData: data });
        } catch (error) {
          console.error('Error refreshing watchlist data:', error);
          // Don't set error state for refresh failures
        }
      },

      // ========================================================================
      // Paper Trading Actions
      // ========================================================================

      // Initialize paper trading account
      initializePaperAccount: async () => {
        set({ error: null });

        try {
          await tradingService.initializePaperAccount();
          // Fetch balance after initialization
          await get().fetchPaperBalance();
          await get().fetchPaperPortfolio();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to initialize paper account';
          set({ error: errorMessage });
          console.error('Error initializing paper account:', error);
        }
      },

      // Fetch paper trading balance
      fetchPaperBalance: async () => {
        set({ loadingPaperBalance: true, error: null });

        try {
          const balance = await tradingService.getPaperBalances();
          set({ paperBalance: balance, loadingPaperBalance: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch paper balance';
          set({ error: errorMessage, loadingPaperBalance: false, paperBalance: null });
          console.error('Error fetching paper balance:', error);
        }
      },

      // Fetch paper trading positions
      fetchPaperPositions: async () => {
        set({ loadingPaperPositions: true, error: null });

        try {
          const positions = await tradingService.getPaperPositions('open');
          set({ paperPositions: positions, loadingPaperPositions: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch paper positions';
          set({ error: errorMessage, loadingPaperPositions: false, paperPositions: [] });
          console.error('Error fetching paper positions:', error);
        }
      },

      // Fetch paper trading trades history
      fetchPaperTrades: async () => {
        set({ loadingPaperTrades: true, error: null });

        try {
          const trades = await tradingService.getPaperTrades();
          set({ paperTrades: trades, loadingPaperTrades: false });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch paper trades';
          set({ error: errorMessage, loadingPaperTrades: false, paperTrades: [] });
          console.error('Error fetching paper trades:', error);
        }
      },

      // Fetch paper trading portfolio summary
      fetchPaperPortfolio: async () => {
        set({ error: null });

        try {
          const portfolio = await tradingService.getPaperPortfolio();
          set({ paperPortfolio: portfolio });
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to fetch paper portfolio';
          set({ error: errorMessage, paperPortfolio: null });
          console.error('Error fetching paper portfolio:', error);
        }
      },

      // Create paper trading order
      createOrder: async (orderData: CreateOrderInput) => {
        set({ error: null });

        try {
          await tradingService.createPaperOrder(orderData);
          // Refresh data after creating order
          await get().fetchPaperBalance();
          await get().fetchPaperPositions();
          await get().fetchPaperPortfolio();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to create order';
          set({ error: errorMessage });
          console.error('Error creating order:', error);
          throw error; // Re-throw to handle in component
        }
      },

      // Close paper trading position
      closePosition: async (positionId: string) => {
        set({ error: null });

        try {
          await tradingService.closePaperPosition(positionId);
          // Refresh data after closing position
          await get().fetchPaperBalance();
          await get().fetchPaperPositions();
          await get().fetchPaperTrades();
          await get().fetchPaperPortfolio();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to close position';
          set({ error: errorMessage });
          console.error('Error closing position:', error);
          throw error; // Re-throw to handle in component
        }
      },

      // Reset paper trading account
      resetPaperAccount: async () => {
        set({ error: null });

        try {
          await tradingService.resetPaperAccount();
          // Refresh all data after reset
          await get().fetchPaperBalance();
          await get().fetchPaperPositions();
          await get().fetchPaperTrades();
          await get().fetchPaperPortfolio();
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Failed to reset paper account';
          set({ error: errorMessage });
          console.error('Error resetting paper account:', error);
        }
      },
    }),
    {
      name: 'trading-store',
    }
  )
);

// ============================================================================
// Selectors (for performance optimization)
// ============================================================================

export const useSelectedSymbol = () => useTradingStore((state) => state.selectedSymbol);
export const useTimeframe = () => useTradingStore((state) => state.timeframe);
export const useKlines = () => useTradingStore((state) => state.klines);
export const useCurrentTicker = () => useTradingStore((state) => state.currentTicker);
export const useOrderBook = () => useTradingStore((state) => state.orderBook);
export const useLoadingKlines = () => useTradingStore((state) => state.loadingKlines);
export const useTradingError = () => useTradingStore((state) => state.error);
export const useWatchlist = () => useTradingStore((state) => state.watchlist);
export const useWatchlistData = () => useTradingStore((state) => state.watchlistData);
export const useLoadingWatchlist = () => useTradingStore((state) => state.loadingWatchlist);

export default useTradingStore;
