import { useMemo, useState, useCallback } from 'react';
import { useMarketStore } from '../stores/marketStore';
import type { OrderBookEntry } from '../types/models';

export type PricePrecision = 0.01 | 0.1 | 1 | 10;

interface UseOrderBookOptions {
  symbol?: string;
  maxRows?: number;
  defaultPrecision?: PricePrecision;
}

interface GroupedEntry {
  price: number;
  quantity: number;
  total: number;
}

export function useOrderBook({
  symbol,
  maxRows = 8,
  defaultPrecision = 0.01,
}: UseOrderBookOptions = {}) {
  const [precision, setPrecision] = useState<PricePrecision>(defaultPrecision);
  const orderBook = useMarketStore((state) =>
    symbol ? state.orderBook[symbol] : undefined
  );

  // Group entries by precision
  const groupByPrecision = useCallback(
    (entries: OrderBookEntry[]): GroupedEntry[] => {
      const groups = new Map<number, GroupedEntry>();

      entries.forEach((entry) => {
        const groupedPrice = Math.floor(entry.price / precision) * precision;

        if (groups.has(groupedPrice)) {
          const existing = groups.get(groupedPrice)!;
          existing.quantity += entry.quantity;
          existing.total += entry.price * entry.quantity;
        } else {
          groups.set(groupedPrice, {
            price: groupedPrice,
            quantity: entry.quantity,
            total: entry.price * entry.quantity,
          });
        }
      });

      return Array.from(groups.values())
        .sort((a, b) => b.price - a.price)
        .slice(0, maxRows);
    },
    [precision, maxRows]
  );

  // Process bids and asks
  const { bids, asks, maxQuantity } = useMemo(() => {
    if (!orderBook) {
      return { bids: [], asks: [], maxQuantity: 1 };
    }

    const processedBids = groupByPrecision(orderBook.bids).sort(
      (a, b) => b.price - a.price
    );
    const processedAsks = groupByPrecision(orderBook.asks).sort(
      (a, b) => a.price - b.price
    );

    const allQuantities = [
      ...processedBids.map((b) => b.quantity),
      ...processedAsks.map((a) => a.quantity),
    ];

    const maxQty = allQuantities.length > 0 ? Math.max(...allQuantities) : 1;

    return {
      bids: processedBids,
      asks: processedAsks,
      maxQuantity: maxQty,
    };
  }, [orderBook, groupByPrecision]);

  // Calculate mid price and spread
  const { midPrice, spread, spreadPercent } = useMemo(() => {
    const bestBid = bids[0]?.price || 0;
    const bestAsk = asks[0]?.price || 0;

    if (bestBid && bestAsk) {
      const mid = (bestBid + bestAsk) / 2;
      const spreadVal = bestAsk - bestBid;
      const spreadPct = (spreadVal / mid) * 100;
      return { midPrice: mid, spread: spreadVal, spreadPercent: spreadPct };
    }

    return {
      midPrice: bestBid || bestAsk || 0,
      spread: 0,
      spreadPercent: 0,
    };
  }, [bids, asks]);

  // Calculate buy/sell ratio
  const { buyRatio, sellRatio } = useMemo(() => {
    const totalBidQty = bids.reduce((sum, b) => sum + b.quantity, 0);
    const totalAskQty = asks.reduce((sum, a) => sum + a.quantity, 0);
    const total = totalBidQty + totalAskQty;

    if (total === 0) {
      return { buyRatio: 50, sellRatio: 50 };
    }

    const buyPct = (totalBidQty / total) * 100;
    return {
      buyRatio: buyPct,
      sellRatio: 100 - buyPct,
    };
  }, [bids, asks]);

  // Calculate totals for cumulative depth
  const bidsWithTotal = useMemo(() => {
    let cumulative = 0;
    return bids.map((bid) => {
      cumulative += bid.quantity;
      return { ...bid, cumulative };
    });
  }, [bids]);

  const asksWithTotal = useMemo(() => {
    let cumulative = 0;
    return asks.map((ask) => {
      cumulative += ask.quantity;
      return { ...ask, cumulative };
    });
  }, [asks]);

  return {
    // Data
    bids: bidsWithTotal,
    asks: asksWithTotal,
    maxQuantity,
    midPrice,
    spread,
    spreadPercent,
    buyRatio,
    sellRatio,
    precision,

    // Actions
    setPrecision,

    // State
    isLoading: !orderBook,
    lastUpdate: orderBook?.timestamp,
  };
}
