import { Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Cron, CronExpression } from '@nestjs/schedule';
import { MarketService } from './market.service';
import { MarketGateway } from './market.gateway';
import { PrismaService } from '@common/prisma/prisma.service';
import { TickData, KLineData } from './interfaces/market.interface';

@Injectable()
export class MarketDataFeedService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(MarketDataFeedService.name);
  private readonly mockSymbols = ['SC', 'AU', 'CU', 'AG', 'I', 'M', 'P', 'EC'];
  private mockDataInterval: NodeJS.Timeout;
  private isRunning = false;

  constructor(
    private readonly configService: ConfigService,
    private readonly marketService: MarketService,
    private readonly marketGateway: MarketGateway,
    private readonly prisma: PrismaService,
  ) {}

  async onModuleInit() {
    // 启动模拟数据feed
    const provider = this.configService.get('marketData.provider');
    
    if (provider === 'mock') {
      this.startMockDataFeed();
      this.logger.log('📊 启动模拟行情数据服务');
    } else {
      // TODO: 实现真实数据源连接
      this.logger.log(`📊 使用数据源: ${provider}`);
    }
  }

  onModuleDestroy() {
    this.stopMockDataFeed();
  }

  // 启动模拟数据推送
  private startMockDataFeed() {
    if (this.isRunning) return;
    
    this.isRunning = true;
    const interval = this.configService.get('marketData.tickUpdateInterval') || 1000;
    
    this.mockDataInterval = setInterval(() => {
      this.generateAndBroadcastMockData();
    }, interval);
  }

  // 停止模拟数据推送
  private stopMockDataFeed() {
    this.isRunning = false;
    if (this.mockDataInterval) {
      clearInterval(this.mockDataInterval);
    }
  }

  // 生成并广播模拟数据
  private async generateAndBroadcastMockData() {
    for (const symbol of this.mockSymbols) {
      try {
        const tick = await this.generateMockTick(symbol);
        
        // 存储到Redis
        await this.marketService.storeTickData(symbol, tick);
        
        // 广播给订阅的客户端
        this.marketGateway.broadcastTick(symbol, tick);
      } catch (error) {
        this.logger.error(`生成模拟数据失败 ${symbol}:`, error.message);
      }
    }
  }

  // 定时推送市场概览
  @Cron(CronExpression.EVERY_30_SECONDS)
  async broadcastMarketOverview() {
    try {
      const overview = await this.marketService.getMarketOverview();
      this.marketGateway.broadcastMarketOverview(overview);
    } catch (error) {
      this.logger.error('广播市场概览失败:', error.message);
    }
  }

  // 生成模拟Tick数据
  private async generateMockTick(symbol: string): Promise<TickData> {
    // 获取当前价格或生成基础价格
    const currentTick = await this.marketService.getTickData(symbol).catch(() => null);
    let basePrice = 500;
    
    if (currentTick) {
      basePrice = currentTick.price;
    } else {
      // 根据品种设置不同的基础价格
      const basePrices: Record<string, number> = {
        SC: 528.6,  // 原油
        AU: 685.2,  // 黄金
        CU: 80610,  // 铜
        AG: 8250,   // 白银
        I: 785.5,   // 铁矿石
        M: 2985,    // 豆粕
        P: 8750,    // 棕榈油
        EC: 2150,   // 集运指数
      };
      basePrice = basePrices[symbol] || 500;
    }

    // 随机波动 (0.1% - 0.5%)
    const volatility = basePrice * (0.001 + Math.random() * 0.004);
    const change = (Math.random() - 0.5) * volatility;
    const price = basePrice + change;

    return {
      symbol,
      price: Number(price.toFixed(2)),
      change: Number(change.toFixed(2)),
      changePercent: Number(((change / basePrice) * 100).toFixed(2)),
      open: currentTick?.open || basePrice,
      high: Math.max(currentTick?.high || price, price) * (1 + Math.random() * 0.001),
      low: Math.min(currentTick?.low || price, price) * (1 - Math.random() * 0.001),
      volume: Math.floor(Math.random() * 10000) + (currentTick?.volume || 0),
      openInterest: Math.floor(Math.random() * 100000),
      bidPrice: price - 0.1,
      askPrice: price + 0.1,
      bidVolume: Math.floor(Math.random() * 100),
      askVolume: Math.floor(Math.random() * 100),
      timestamp: Date.now(),
    };
  }

  // 生成模拟K线数据
  async generateMockKline(symbol: string, period: string, count: number = 100): Promise<KLineData[]> {
    const data: KLineData[] = [];
    const product = await this.prisma.product.findUnique({
      where: { symbol },
    });
    
    let basePrice = 500;
    if (product) {
      const tick = await this.marketService.getTickData(symbol);
      basePrice = tick.price;
    }

    const now = new Date();
    const periodMinutes = this.parsePeriod(period);

    for (let i = count; i >= 0; i--) {
      const time = new Date(now.getTime() - i * periodMinutes * 60 * 1000);
      const volatility = basePrice * 0.008;
      const change = (Math.random() - 0.48) * volatility;

      const open = basePrice;
      const close = basePrice + change;
      const high = Math.max(open, close) + Math.random() * volatility * 0.5;
      const low = Math.min(open, close) - Math.random() * volatility * 0.5;
      const volume = Math.floor(Math.random() * 10000 + 5000);

      data.push({
        time: time.toISOString(),
        open: Number(open.toFixed(2)),
        high: Number(high.toFixed(2)),
        low: Number(low.toFixed(2)),
        close: Number(close.toFixed(2)),
        volume,
      });

      basePrice = close;
    }

    return data;
  }

  private parsePeriod(period: string): number {
    const periodMap: Record<string, number> = {
      '1m': 1,
      '5m': 5,
      '15m': 15,
      '30m': 30,
      '1h': 60,
      '1d': 60 * 24,
      '1w': 60 * 24 * 7,
    };
    return periodMap[period] || 5;
  }
}
