import { GenericCrudService } from '@/server/utils/generic-crud.service';
import { DataSource, Repository } from 'typeorm';
import { StockData } from './stock-data.entity';
import debug from 'debug';
import dayjs from 'dayjs';

const log = {
  api: debug('backend:api:stock'),
  db: debug('backend:db:stock'),
};

interface StockPriceData {
  t: string;  // 交易时间
  o: number;  // 开盘价
  h: number;  // 最高价
  l: number;  // 最低价
  c: number;  // 收盘价
  v: number;  // 成交量
  a: number;  // 成交额
  pc: number; // 前收盘价
  sf: number; // 停牌状态
}

interface StockStopPrice {
  t: string;  // 交易日期
  h: number;  // 涨停价格
  l: number;  // 跌停价格
}

interface StockIndicator {
  time: string;  // 更新时间
  lb: number;    // 量比
  om: number;    // 1分钟涨速(%)
  fm: number;    // 5分钟涨速(%)
  '3d': number;  // 3日涨幅(%)
  '5d': number;  // 5日涨幅(%)
  '10d': number; // 10日涨幅(%)
  '3t': number;  // 3日换手(%)
  '5t': number;  // 5日换手(%)
  '10t': number; // 10日换手(%)
}

export class StockDataService extends GenericCrudService<StockData> {
  constructor(dataSource: DataSource) {
    super(dataSource, StockData);
  }

  private getApiBaseUrl(): string {
    return 'https://api.mairuiapi.com/hsstock';
  }

  private getLicense(): string {
    const license = process.env.STOCK_API_LICENSE;
    if (!license) {
      throw new Error('STOCK_API_LICENSE environment variable not set');
    }
    return license;
  }

  /**
   * 获取股票历史数据
   * 优先从数据库获取，如果没有则调用外部API
   * 使用新的股票API接口获取历史分时交易数据
   * @param code 股票代码
   * @param market 市场代码（如SZ、SH）
   * @param level 分时级别（d日线、w周线、m月线、y年线、5/15/30/60分钟）
   * @param startDate 开始时间（YYYYMMDD格式）
   * @param endDate 结束时间（YYYYMMDD格式）
   * @param limit 获取数据条数
   * @returns 股票历史数据
   */
  async getStockHistory(
    code: string,
    market: string = 'SZ',
    level: string = 'd',
    startDate?: string,
    endDate?: string,
    limit?: number
  ): Promise<StockPriceData[]> {
    try {
      // 构建缓存键
      const cacheKey = `${code}.${market}_${level}_${startDate || ''}_${endDate || ''}_${limit || ''}`;
      
      // 查询数据库中是否存在今天的数据
      const today = dayjs().format('YYYY-MM-DD');
      const existingData = await this.repository
        .createQueryBuilder('stock')
        .where('stock.code = :cacheKey', { cacheKey })
        .andWhere('stock.updated_at >= :today', { today: `${today} 00:00:00` })
        .getOne();

      if (existingData) {
        log.db(`Found existing data for ${cacheKey} on ${today}`);
        return existingData.data as StockPriceData[];
      }

      // 如果没有今天的数据，调用外部API
      log.api(`Fetching fresh data for ${cacheKey} from external API`);
      const license = this.getLicense();
      let apiUrl = `${this.getApiBaseUrl()}/history/${code}.${market}/${level}/n/${license}`;
      
      const params = new URLSearchParams();
      if (startDate) params.append('st', startDate);
      if (endDate) params.append('et', endDate);
      if (limit) params.append('lt', limit.toString());
      
      const queryString = params.toString();
      if (queryString) {
        apiUrl += `?${queryString}`;
      }

      log.api(`Fetching stock history from: ${apiUrl}`);
      
      const response = await fetch(apiUrl, {
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        }
      });

      if (!response.ok) {
        throw new Error(`API request failed with status ${response.status}`);
      }

      const newData: StockPriceData[] = await response.json();
      
      // 更新或插入数据库
      const stockData = new StockData();
      stockData.code = cacheKey;
      stockData.data = newData;
      
      await this.repository
        .createQueryBuilder()
        .insert()
        .values(stockData)
        .orUpdate(
          ['data', 'updated_at'],
          ['code']
        )
        .execute();

      log.api(`Successfully saved fresh data for ${cacheKey}`);
      return newData;
    } catch (error) {
      log.api('Error getting stock history:', error);
      throw error;
    }
  }

  /**
   * 获取股票最新数据
   * 优先从数据库获取，如果没有则调用外部API
   * 使用新的股票API接口获取最新分时交易数据
   * @param code 股票代码
   * @param market 市场代码（如SZ、SH）
   * @param level 分时级别（d日线、w周线、m月线、y年线、5/15/30/60分钟）
   * @param limit 获取数据条数
   * @returns 股票最新数据
   */
  async getLatestStockData(
    code: string,
    market: string = 'SZ',
    level: string = 'd',
    limit: number = 1
  ): Promise<StockPriceData[]> {
    try {
      // 构建缓存键
      const cacheKey = `latest_${code}.${market}_${level}_${limit}`;
      
      // 查询数据库中是否存在今天的数据
      const today = dayjs().format('YYYY-MM-DD');
      const existingData = await this.repository
        .createQueryBuilder('stock')
        .where('stock.code = :cacheKey', { cacheKey })
        .andWhere('stock.updated_at >= :today', { today: `${today} 00:00:00` })
        .getOne();

      if (existingData) {
        log.db(`Found existing latest data for ${cacheKey} on ${today}`);
        return existingData.data as StockPriceData[];
      }

      // 如果没有今天的数据，调用外部API
      log.api(`Fetching fresh latest data for ${cacheKey} from external API`);
      const license = this.getLicense();
      const apiUrl = `${this.getApiBaseUrl()}/latest/${code}.${market}/${level}/n/${license}?lt=${limit}`;

      log.api(`Fetching latest stock data from: ${apiUrl}`);
      
      const response = await fetch(apiUrl, {
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        }
      });

      if (!response.ok) {
        throw new Error(`API request failed with status ${response.status}`);
      }

      const newData: StockPriceData[] = await response.json();
      
      // 更新或插入数据库
      const stockData = new StockData();
      stockData.code = cacheKey;
      stockData.data = newData;
      
      await this.repository
        .createQueryBuilder()
        .insert()
        .values(stockData)
        .orUpdate(
          ['data', 'updated_at'],
          ['code']
        )
        .execute();

      log.api(`Successfully saved fresh latest data for ${cacheKey}`);
      return newData;
    } catch (error) {
      log.api('Error getting latest stock data:', error);
      throw error;
    }
  }

  /**
   * 获取股票历史涨跌停价格
   * @param code 股票代码
   * @param market 市场代码（如SZ、SH）
   * @param startDate 开始时间（YYYYMMDD格式）
   * @param endDate 结束时间（YYYYMMDD格式）
   * @returns 涨跌停价格数据
   */
  async getStockStopPrice(
    code: string,
    market: string = 'SZ',
    startDate?: string,
    endDate?: string
  ): Promise<StockStopPrice[]> {
    try {
      const license = this.getLicense();
      let apiUrl = `${this.getApiBaseUrl()}/stopprice/history/${code}.${market}/${license}`;
      
      const params = new URLSearchParams();
      if (startDate) params.append('st', startDate);
      if (endDate) params.append('et', endDate);
      
      const queryString = params.toString();
      if (queryString) {
        apiUrl += `?${queryString}`;
      }

      log.api(`Fetching stock stop price from: ${apiUrl}`);
      
      const response = await fetch(apiUrl, {
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        }
      });

      if (!response.ok) {
        throw new Error(`API request failed with status ${response.status}`);
      }

      const data: StockStopPrice[] = await response.json();
      log.api(`Successfully fetched ${data.length} stop price records for ${code}.${market}`);
      
      return data;
    } catch (error) {
      log.api('Error getting stock stop price:', error);
      throw error;
    }
  }

  /**
   * 获取股票行情指标
   * @param code 股票代码
   * @param market 市场代码（如SZ、SH）
   * @param startDate 开始时间（YYYYMMDD格式）
   * @param endDate 结束时间（YYYYMMDD格式）
   * @returns 行情指标数据
   */
  async getStockIndicators(
    code: string,
    market: string = 'SZ',
    startDate?: string,
    endDate?: string
  ): Promise<StockIndicator[]> {
    try {
      const license = this.getLicense();
      let apiUrl = `${this.getApiBaseUrl()}/indicators/${code}.${market}/${license}`;
      
      const params = new URLSearchParams();
      if (startDate) params.append('st', startDate);
      if (endDate) params.append('et', endDate);
      
      const queryString = params.toString();
      if (queryString) {
        apiUrl += `?${queryString}`;
      }

      log.api(`Fetching stock indicators from: ${apiUrl}`);
      
      const response = await fetch(apiUrl, {
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        }
      });

      if (!response.ok) {
        throw new Error(`API request failed with status ${response.status}`);
      }

      const data: StockIndicator[] = await response.json();
      log.api(`Successfully fetched ${data.length} indicator records for ${code}.${market}`);
      
      return data;
    } catch (error) {
      log.api('Error getting stock indicators:', error);
      throw error;
    }
  }

  /**
   * 获取股票最新数据（兼容旧方法）
   * @param code 股票代码
   * @returns 股票最新数据
   */
  async getLatestStockDataOld(code: string): Promise<StockData | null> {
    try {
      const stockData = await this.repository
        .createQueryBuilder('stock')
        .where('stock.code = :code', { code })
        .orderBy('stock.updatedAt', 'DESC')
        .getOne();

      return stockData;
    } catch (error) {
      log.db('Error fetching latest stock data:', error);
      throw error;
    }
  }

  /**
   * 获取多个股票的历史数据（兼容旧方法）
   * @param codes 股票代码数组
   * @returns 股票历史数据映射
   */
  async getMultipleStockHistories(codes: string[]): Promise<Record<string, any>> {
    const results: Record<string, any> = {};
    
    for (const code of codes) {
      try {
        const [stockCode, market] = code.includes('.') ? code.split('.') : [code, 'SZ'];
        results[code] = await this.getStockHistory(stockCode, market);
      } catch (error) {
        log.api(`Error fetching data for ${code}:`, error);
        results[code] = null;
      }
    }
    
    return results;
  }

  /**
   * 获取股票完整信息
   * @param code 股票代码
   * @param market 市场代码
   * @returns 包含历史数据、最新数据、涨跌停价格和指标的完整信息
   */
  async getStockCompleteInfo(
    code: string,
    market: string = 'SZ'
  ): Promise<{
    history: StockPriceData[];
    latest: StockPriceData[];
    stopPrice: StockStopPrice[];
    indicators: StockIndicator[];
  }> {
    try {
      const [history, latest, stopPrice, indicators] = await Promise.all([
        this.getStockHistory(code, market),
        this.getLatestStockData(code, market),
        this.getStockStopPrice(code, market),
        this.getStockIndicators(code, market)
      ]);

      return {
        history,
        latest,
        stopPrice,
        indicators
      };
    } catch (error) {
      log.api('Error getting stock complete info:', error);
      throw error;
    }
  }
}