/**
 * Risk Check Middleware
 *
 * Pre-trade risk validation to ensure orders comply with risk limits.
 *
 * @version 1.0.0
 * @author Trading Platform Trading Platform
 */

import { riskConfig } from '../config';
import { getBinanceClient } from '../services/binance-client';
import { logger } from '../utils/logger';

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

export interface RiskCheckParams {
  symbol: string;
  side: 'buy' | 'sell';
  amount: number;
  price?: number;
}

export interface RiskCheckResult {
  allowed: boolean;
  reason?: string;
  warnings?: string[];
  orderValue?: number;
}

// Daily volume tracking (in-memory, resets on restart)
let dailyVolume = 0;
let lastVolumeResetDate = new Date().toDateString();

// ==========================================
// Risk Check Functions
// ==========================================

/**
 * Reset daily volume counter at midnight
 */
function checkAndResetDailyVolume(): void {
  const today = new Date().toDateString();
  if (today !== lastVolumeResetDate) {
    dailyVolume = 0;
    lastVolumeResetDate = today;
    logger.info('Daily volume counter reset');
  }
}

/**
 * Get the quote asset from a symbol (e.g., USDT from BTCUSDT)
 */
function getQuoteAsset(symbol: string): string {
  const stablecoins = ['USDT', 'BUSD', 'USDC', 'TUSD', 'DAI'];
  for (const stable of stablecoins) {
    if (symbol.endsWith(stable)) {
      return stable;
    }
  }
  return 'USDT';
}

/**
 * Perform comprehensive risk check before order execution
 */
export async function performRiskCheck(params: RiskCheckParams): Promise<RiskCheckResult> {
  const { symbol, side, amount, price } = params;
  const warnings: string[] = [];

  try {
    checkAndResetDailyVolume();

    const client = getBinanceClient();

    // 1. Get current price if not provided
    let orderPrice = price;
    if (!orderPrice) {
      try {
        orderPrice = await client.getCurrentPrice(symbol);
      } catch (error) {
        logger.warn(`Could not fetch current price for ${symbol}, using amount as value estimate`);
        orderPrice = 1; // Fallback
      }
    }

    // 2. Calculate order value in quote currency (usually USDT)
    const orderValue = amount * orderPrice;

    // 3. Check maximum order value
    if (orderValue > riskConfig.maxOrderValueUsdt) {
      return {
        allowed: false,
        reason: `Order value ${orderValue.toFixed(2)} USDT exceeds maximum ${riskConfig.maxOrderValueUsdt} USDT`,
        orderValue,
      };
    }

    // 4. Check daily volume limit
    if (dailyVolume + orderValue > riskConfig.maxDailyVolumeUsdt) {
      return {
        allowed: false,
        reason: `Daily volume limit reached. Current: ${dailyVolume.toFixed(2)} USDT, Limit: ${riskConfig.maxDailyVolumeUsdt} USDT`,
        orderValue,
      };
    }

    // 5. Check if API keys are configured for trading
    if (!client.isConfigured()) {
      return {
        allowed: false,
        reason: 'Binance API keys are not configured. Cannot execute trades.',
        orderValue,
      };
    }

    // 6. Verify we can connect to Binance
    const connected = await client.isConnected();
    if (!connected) {
      return {
        allowed: false,
        reason: 'Cannot connect to Binance. Please check your network and API configuration.',
        orderValue,
      };
    }

    // 7. Check balance for buy orders (if we have account access)
    if (side === 'buy') {
      try {
        const account = await client.getAccount();
        const quoteAsset = getQuoteAsset(symbol);
        const quoteBalance = account.balances.find(b => b.asset === quoteAsset);
        const available = quoteBalance?.free ?? 0;

        if (available < orderValue) {
          return {
            allowed: false,
            reason: `Insufficient ${quoteAsset} balance. Required: ${orderValue.toFixed(2)}, Available: ${available.toFixed(2)}`,
            orderValue,
          };
        }

        // Warning if using more than 50% of available balance
        if (orderValue > available * 0.5) {
          warnings.push(`This order uses ${((orderValue / available) * 100).toFixed(1)}% of your available ${quoteAsset}`);
        }
      } catch (error) {
        warnings.push('Could not verify account balance');
        logger.warn('Balance check failed', { error });
      }
    }

    // 8. Check for large order warning
    if (orderValue > riskConfig.maxOrderValueUsdt * 0.5) {
      warnings.push(`Large order: ${orderValue.toFixed(2)} USDT (${((orderValue / riskConfig.maxOrderValueUsdt) * 100).toFixed(0)}% of max)`);
    }

    // All checks passed
    return {
      allowed: true,
      orderValue,
      warnings: warnings.length > 0 ? warnings : undefined,
    };
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    logger.error('Risk check failed', { error, params });
    return {
      allowed: false,
      reason: `Risk check error: ${message}`,
    };
  }
}

/**
 * Record executed trade volume
 */
export function recordTradeVolume(orderValue: number): void {
  checkAndResetDailyVolume();
  dailyVolume += orderValue;
  logger.info(`Trade recorded. Daily volume: ${dailyVolume.toFixed(2)} USDT`);
}

/**
 * Get current daily volume
 */
export function getDailyVolume(): number {
  checkAndResetDailyVolume();
  return dailyVolume;
}

/**
 * Get remaining daily volume allowance
 */
export function getRemainingDailyVolume(): number {
  checkAndResetDailyVolume();
  return Math.max(0, riskConfig.maxDailyVolumeUsdt - dailyVolume);
}

// ==========================================
// Exports
// ==========================================

export default {
  performRiskCheck,
  recordTradeVolume,
  getDailyVolume,
  getRemainingDailyVolume,
};
