/**
 * Binance Market Data Tools
 *
 * - binance_get_ticker: Get current price and 24h stats
 * - binance_get_orderbook: Get order book depth
 * - binance_get_klines: Get OHLCV candles
 *
 * @version 1.0.0
 * @author Trading Platform Trading Platform
 */

import { z } from 'zod';
import { getBinanceClient, BinanceTicker, BinanceOrderBook, BinanceKline } from '../services/binance-client';

// ==========================================
// binance_get_ticker
// ==========================================

/**
 * Tool: binance_get_ticker
 * Get current price and 24h statistics for a trading pair
 */
export const binanceGetTickerSchema = {
  name: 'binance_get_ticker',
  description: 'Get the current price and 24-hour statistics for a Binance trading pair',
  inputSchema: {
    type: 'object' as const,
    properties: {
      symbol: {
        type: 'string',
        description: 'Trading pair symbol (e.g., BTCUSDT, ETHUSDT, BNBUSDT)',
      },
    },
    required: ['symbol'] as string[],
  },
};

export const BinanceGetTickerInputSchema = z.object({
  symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()),
});

export type BinanceGetTickerInput = z.infer<typeof BinanceGetTickerInputSchema>;

export interface BinanceGetTickerResult {
  success: boolean;
  data?: BinanceTicker;
  error?: string;
}

export async function binance_get_ticker(
  params: BinanceGetTickerInput
): Promise<BinanceGetTickerResult> {
  try {
    const client = getBinanceClient();
    const ticker = await client.getTicker(params.symbol);

    return {
      success: true,
      data: ticker,
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error occurred',
    };
  }
}

export async function handleBinanceGetTicker(
  params: unknown
): Promise<{ content: Array<{ type: string; text: string }> }> {
  const validatedParams = BinanceGetTickerInputSchema.parse(params);
  const result = await binance_get_ticker(validatedParams);

  if (result.success && result.data) {
    const d = result.data;
    const changeSymbol = d.change24h >= 0 ? '+' : '';

    const formattedOutput = `
Binance Ticker: ${d.symbol}
${'='.repeat(35)}
Current Price: $${d.price.toFixed(getPriceDecimals(d.symbol))}
Bid: $${d.bid.toFixed(getPriceDecimals(d.symbol))}
Ask: $${d.ask.toFixed(getPriceDecimals(d.symbol))}

24h Statistics
--------------
High: $${d.high24h.toFixed(getPriceDecimals(d.symbol))}
Low: $${d.low24h.toFixed(getPriceDecimals(d.symbol))}
Volume: ${formatVolume(d.volume24h)}
Change: ${changeSymbol}${d.change24h.toFixed(2)}%

Last Update: ${new Date(d.timestamp).toISOString()}
`.trim();

    return {
      content: [{ type: 'text', text: formattedOutput }],
    };
  }

  return {
    content: [{ type: 'text', text: `Error: ${result.error}` }],
  };
}

// ==========================================
// binance_get_orderbook
// ==========================================

/**
 * Tool: binance_get_orderbook
 * Get order book (bids and asks) with specified depth
 */
export const binanceGetOrderbookSchema = {
  name: 'binance_get_orderbook',
  description: 'Get the order book (bids and asks) with the specified depth for a trading pair',
  inputSchema: {
    type: 'object' as const,
    properties: {
      symbol: {
        type: 'string',
        description: 'Trading pair symbol (e.g., BTCUSDT)',
      },
      limit: {
        type: 'number',
        description: 'Order book depth (5, 10, 20, 50, or 100). Default: 20',
      },
    },
    required: ['symbol'] as string[],
  },
};

export const BinanceGetOrderbookInputSchema = z.object({
  symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()),
  limit: z.number().int().min(5).max(100).default(20),
});

export type BinanceGetOrderbookInput = z.infer<typeof BinanceGetOrderbookInputSchema>;

export interface BinanceGetOrderbookResult {
  success: boolean;
  data?: BinanceOrderBook;
  error?: string;
}

export async function binance_get_orderbook(
  params: BinanceGetOrderbookInput
): Promise<BinanceGetOrderbookResult> {
  try {
    const client = getBinanceClient();
    const orderbook = await client.getOrderBook(params.symbol, params.limit);

    return {
      success: true,
      data: orderbook,
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error occurred',
    };
  }
}

export async function handleBinanceGetOrderbook(
  params: unknown
): Promise<{ content: Array<{ type: string; text: string }> }> {
  const validatedParams = BinanceGetOrderbookInputSchema.parse(params);
  const result = await binance_get_orderbook(validatedParams);

  if (result.success && result.data) {
    const d = result.data;
    const decimals = getPriceDecimals(d.symbol);

    // Format top 10 levels
    const topBids = d.bids.slice(0, 10);
    const topAsks = d.asks.slice(0, 10);

    let bidsStr = topBids
      .map(([price, qty]) => `  $${price.toFixed(decimals)} | ${qty.toFixed(6)}`)
      .join('\n');

    let asksStr = topAsks
      .map(([price, qty]) => `  $${price.toFixed(decimals)} | ${qty.toFixed(6)}`)
      .join('\n');

    const formattedOutput = `
Order Book: ${d.symbol}
${'='.repeat(35)}
Spread: $${d.spread.toFixed(decimals)} (${d.spreadPercentage.toFixed(4)}%)

Top ${topAsks.length} Asks (Sell Orders)
${'-'.repeat(25)}
${asksStr}

Top ${topBids.length} Bids (Buy Orders)
${'-'.repeat(25)}
${bidsStr}

Timestamp: ${new Date(d.timestamp).toISOString()}
`.trim();

    return {
      content: [{ type: 'text', text: formattedOutput }],
    };
  }

  return {
    content: [{ type: 'text', text: `Error: ${result.error}` }],
  };
}

// ==========================================
// binance_get_klines
// ==========================================

/**
 * Tool: binance_get_klines
 * Get historical OHLCV candles for technical analysis
 */
export const binanceGetKlinesSchema = {
  name: 'binance_get_klines',
  description: 'Get historical candlestick (OHLCV) data for technical analysis',
  inputSchema: {
    type: 'object' as const,
    properties: {
      symbol: {
        type: 'string',
        description: 'Trading pair symbol (e.g., BTCUSDT)',
      },
      interval: {
        type: 'string',
        description: 'Candle interval: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w. Default: 5m',
        enum: ['1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w'],
      },
      limit: {
        type: 'number',
        description: 'Number of candles to retrieve (max 500). Default: 100',
      },
    },
    required: ['symbol'] as string[],
  },
};

export const BinanceGetKlinesInputSchema = z.object({
  symbol: z.string().min(1).max(20).transform((s) => s.toUpperCase()),
  interval: z.enum(['1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w']).default('5m'),
  limit: z.number().int().min(1).max(500).default(100),
});

export type BinanceGetKlinesInput = z.infer<typeof BinanceGetKlinesInputSchema>;

export interface BinanceGetKlinesResult {
  success: boolean;
  data?: {
    symbol: string;
    interval: string;
    candles: BinanceKline[];
    count: number;
  };
  error?: string;
}

export async function binance_get_klines(
  params: BinanceGetKlinesInput
): Promise<BinanceGetKlinesResult> {
  try {
    const client = getBinanceClient();
    const klines = await client.getKlines(params.symbol, params.interval, params.limit);

    return {
      success: true,
      data: {
        symbol: params.symbol,
        interval: params.interval,
        candles: klines,
        count: klines.length,
      },
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error occurred',
    };
  }
}

export async function handleBinanceGetKlines(
  params: unknown
): Promise<{ content: Array<{ type: string; text: string }> }> {
  const validatedParams = BinanceGetKlinesInputSchema.parse(params);
  const result = await binance_get_klines(validatedParams);

  if (result.success && result.data) {
    const d = result.data;
    const decimals = getPriceDecimals(d.symbol);

    // Get last 5 candles for display
    const recentCandles = d.candles.slice(-5);

    let candlesStr = recentCandles
      .map((c) => {
        const time = new Date(c.timestamp).toISOString().slice(0, 16).replace('T', ' ');
        const direction = c.close >= c.open ? 'UP' : 'DOWN';
        return `  ${time} | O:${c.open.toFixed(decimals)} H:${c.high.toFixed(decimals)} L:${c.low.toFixed(decimals)} C:${c.close.toFixed(decimals)} | V:${formatVolume(c.volume)} | ${direction}`;
      })
      .join('\n');

    // Calculate basic stats
    const closes = d.candles.map((c) => c.close);
    const high = Math.max(...d.candles.map((c) => c.high));
    const low = Math.min(...d.candles.map((c) => c.low));
    const avgVolume = d.candles.reduce((sum, c) => sum + c.volume, 0) / d.candles.length;

    const formattedOutput = `
Klines: ${d.symbol} (${d.interval})
${'='.repeat(45)}
Retrieved: ${d.count} candles

Period Statistics
-----------------
Highest High: $${high.toFixed(decimals)}
Lowest Low: $${low.toFixed(decimals)}
Avg Volume: ${formatVolume(avgVolume)}

Recent Candles (last 5)
-----------------------
${candlesStr}

First Candle: ${new Date(d.candles[0].timestamp).toISOString()}
Last Candle: ${new Date(d.candles[d.candles.length - 1].timestamp).toISOString()}
`.trim();

    return {
      content: [{ type: 'text', text: formattedOutput }],
    };
  }

  return {
    content: [{ type: 'text', text: `Error: ${result.error}` }],
  };
}

// ==========================================
// Helper Functions
// ==========================================

/**
 * Get appropriate decimal places for price display
 */
function getPriceDecimals(symbol: string): number {
  const upper = symbol.toUpperCase();

  // Stablecoins and fiat pairs
  if (upper.includes('USD') && !upper.startsWith('BTC') && !upper.startsWith('ETH')) {
    return 4;
  }

  // BTC pairs
  if (upper === 'BTCUSDT' || upper === 'BTCBUSD') {
    return 2;
  }

  // ETH pairs
  if (upper === 'ETHUSDT' || upper === 'ETHBUSD') {
    return 2;
  }

  // Small value coins
  if (upper.includes('SHIB') || upper.includes('DOGE') || upper.includes('PEPE')) {
    return 8;
  }

  // Default
  return 4;
}

/**
 * Format large volume numbers
 */
function formatVolume(volume: number): string {
  if (volume >= 1_000_000_000) {
    return `${(volume / 1_000_000_000).toFixed(2)}B`;
  }
  if (volume >= 1_000_000) {
    return `${(volume / 1_000_000).toFixed(2)}M`;
  }
  if (volume >= 1_000) {
    return `${(volume / 1_000).toFixed(2)}K`;
  }
  return volume.toFixed(4);
}
