# RQData数据适配器
import os
import time
import pandas as pd
from typing import Dict, Optional, List
from qihuo_analyzer.data.api_adapters.base_adapter import BaseDataAdapter

# 尝试导入rqdatac

try:
    import rqdatac as rqd
    RQDATA_AVAILABLE = True
except Exception as e:
    print(f"RQData导入失败：{e}，将使用模拟数据")
    RQDATA_AVAILABLE = False


class RqDataAdapter(BaseDataAdapter):
    """RQData数据适配器
    
    使用RQData获取期货数据。
    """
    
    def __init__(self, username: str = '', password: str = ''):
        self.api_connected = False
        self.username = username
        self.password = password
    
    def connect(self) -> bool:
        """连接API
        
        Returns:
            bool: 连接是否成功
        """
        try:
            if RQDATA_AVAILABLE:
                # 使用RQData连接
                username = self.username or os.getenv('RQDATA_USERNAME', '')
                password = self.password or os.getenv('RQDATA_PASSWORD', '')
                
                if username and password:
                    rqd.init(username, password)
                    print("RQData API连接成功")
                    self.api_connected = True
                    return True
                else:
                    print("RQData账号密码未配置，将使用模拟数据")
                    self.api_connected = False
                    return False
            else:
                # 模拟API，用于测试
                print("RQData不可用，使用模拟API")
                self.api_connected = False
                return False
        except Exception as e:
            print(f"RQData API连接失败：{e}")
            # 模拟API，用于测试
            self.api_connected = False
            return False
    
    def disconnect(self):
        """断开连接"""
        if self.api_connected:
            try:
                # RQData不需要显式断开连接
                print("RQData API连接已断开")
                self.api_connected = False
            except:
                pass
    
    def _convert_duration(self, duration: str) -> str:
        """将时间周期字符串转换为RQData格式
        
        Args:
            duration: 时间周期，如 '1m', '5m', '15m', '1h', '1d'
            
        Returns:
            RQData格式的时间周期
        """
        duration_map = {
            '1m': '1m',
            '5m': '5m',
            '15m': '15m',
            '30m': '30m',
            '1h': '60m',
            '2h': '120m',
            '4h': '240m',
            '6h': '360m',
            '12h': '720m',
            '1d': '1d',
            '1w': '1w'
        }
        return duration_map.get(duration, '60m')  # 默认60分钟
    
    def _convert_symbol(self, symbol: str) -> str:
        """将合约代码转换为RQData格式
        
        Args:
            symbol: 合约代码，如 'CU2603'
            
        Returns:
            RQData格式的合约代码，如 'SHFE.CU2603'
        """
        # 交易所映射
        exchange_map = {
            'CU': 'SHFE',  # 铜 - 上海期货交易所
            'AL': 'SHFE',  # 铝 - 上海期货交易所
            'ZN': 'SHFE',  # 锌 - 上海期货交易所
            'PB': 'SHFE',  # 铅 - 上海期货交易所
            'NI': 'SHFE',  # 镍 - 上海期货交易所
            'SN': 'SHFE',  # 锡 - 上海期货交易所
            'AU': 'SHFE',  # 黄金 - 上海期货交易所
            'AG': 'SHFE',  # 白银 - 上海期货交易所
            'RB': 'SHFE',  # 螺纹钢 - 上海期货交易所
            'HC': 'SHFE',  # 热轧卷板 - 上海期货交易所
            'BU': 'SHFE',  # 沥青 - 上海期货交易所
            'RU': 'SHFE',  # 橡胶 - 上海期货交易所
            'FU': 'SHFE',  # 燃油 - 上海期货交易所
            'SC': 'INE',   # 原油 - 上海国际能源交易中心
            'I': 'DCE',    # 铁矿石 - 大连商品交易所
            'J': 'DCE',    # 焦炭 - 大连商品交易所
            'JM': 'DCE',   # 焦煤 - 大连商品交易所
            'A': 'DCE',    # 大豆 - 大连商品交易所
            'B': 'DCE',    # 豆粕 - 大连商品交易所
            'M': 'DCE',    # 豆粕 - 大连商品交易所
            'Y': 'DCE',    # 豆油 - 大连商品交易所
            'P': 'DCE',    # 棕榈油 - 大连商品交易所
            'C': 'DCE',    # 玉米 - 大连商品交易所
            'CS': 'DCE',   # 玉米淀粉 - 大连商品交易所
            'L': 'DCE',    # 聚乙烯 - 大连商品交易所
            'V': 'DCE',    # 聚氯乙烯 - 大连商品交易所
            'PP': 'DCE',   # 聚丙烯 - 大连商品交易所
            'TA': 'CZCE',  # PTA - 郑州商品交易所
            'CF': 'CZCE',  # 棉花 - 郑州商品交易所
            'SR': 'CZCE',  # 白糖 - 郑州商品交易所
            'MA': 'CZCE',  # 甲醇 - 郑州商品交易所
            'ZC': 'CZCE',  # 动力煤 - 郑州商品交易所
            'FG': 'CZCE',  # 玻璃 - 郑州商品交易所
            'RM': 'CZCE',  # 菜籽粕 - 郑州商品交易所
            'OI': 'CZCE',  # 菜籽油 - 郑州商品交易所
            'RS': 'CZCE',  # 菜籽 - 郑州商品交易所
            'WH': 'CZCE',  # 强麦 - 郑州商品交易所
            'JR': 'CZCE',  # 粳稻 - 郑州商品交易所
            'LR': 'CZCE',  # 晚籼稻 - 郑州商品交易所
        }
        
        # 提取品种代码和合约月份
        if len(symbol) >= 4:
            product_code = symbol[:2].upper()
            contract_month = symbol[2:].upper()
            
            # 获取交易所代码
            exchange = exchange_map.get(product_code, 'SHFE')
            
            # 构建RQData格式的合约代码
            rq_symbol = f"{exchange}.{product_code}{contract_month}"
            return rq_symbol
        else:
            return symbol
    
    def get_kline_data(self, symbol: str, duration: str, count: int = 200) -> Optional[pd.DataFrame]:
        """获取K线数据
        
        Args:
            symbol: 合约代码
            duration: 时间周期，如 '1m', '5m', '15m', '1h', '1d'
            count: 数据数量
            
        Returns:
            K线数据DataFrame，如果无法获取真实数据则返回None
        """
        try:
            if RQDATA_AVAILABLE and self.api_connected:
                # 转换合约代码为RQData格式
                rq_symbol = self._convert_symbol(symbol)
                print(f"使用RQData格式合约代码: {rq_symbol}")
                
                # 转换时间周期为RQData格式
                rq_duration = self._convert_duration(duration)
                
                # 计算开始时间
                from datetime import datetime, timedelta
                end_date = datetime.now()
                
                # 根据时间周期计算开始日期
                if rq_duration == '1d':
                    start_date = end_date - timedelta(days=count)
                elif rq_duration == '1w':
                    start_date = end_date - timedelta(weeks=count)
                else:
                    # 对于分钟级别，计算大致的天数
                    minutes_per_period = int(rq_duration[:-1])
                    total_minutes = minutes_per_period * count
                    start_date = end_date - timedelta(minutes=total_minutes)
                
                # 使用RQData获取K线数据
                df = rqd.get_price(
                    rq_symbol,
                    start_date=start_date,
                    end_date=end_date,
                    frequency=rq_duration,
                    fields=['open', 'high', 'low', 'close', 'volume', 'open_interest'],
                    adjust_type='none'
                )
                
                if not df.empty:
                    print(f"成功获取K线数据，数据长度: {len(df)}")
                    return df
                else:
                    print("获取K线数据失败：无数据返回")
                    return None
            else:
                # 不再自动返回模拟数据，返回None
                print(f"无法获取真实数据：{'API未连接' if not self.api_connected else 'RQData不可用'}")
                return None
        except Exception as e:
            print(f"rqdata获取K线数据失败：{e}")
            # 不再自动返回模拟数据，返回None
            return None
    
    def get_tick_data(self, symbol: str, count: int = 1000) -> Optional[pd.DataFrame]:
        """获取Tick数据"""
        try:
            if RQDATA_AVAILABLE and self.api_connected:
                # 转换合约代码为RQData格式
                rq_symbol = self._convert_symbol(symbol)
                print(f"使用RQData格式合约代码: {rq_symbol}")
                
                # 计算开始时间
                from datetime import datetime, timedelta
                end_date = datetime.now()
                start_date = end_date - timedelta(days=1)  # RQData Tick数据通常只能获取最近1天
                
                # 使用RQData获取Tick数据
                df = rqd.get_price(
                    rq_symbol,
                    start_date=start_date,
                    end_date=end_date,
                    frequency='tick',
                    fields=['last', 'volume', 'open_interest', 'bid_price1', 'bid_volume1', 'ask_price1', 'ask_volume1'],
                    adjust_type='none'
                )
                
                if not df.empty:
                    # 重命名列以保持与原来的接口一致
                    df = df.rename(columns={
                        'last': 'last_price',
                        'bid_price1': 'bid_price1',
                        'bid_volume1': 'bid_volume1',
                        'ask_price1': 'ask_price1',
                        'ask_volume1': 'ask_volume1'
                    })
                    
                    print(f"成功获取Tick数据，数据长度: {len(df)}")
                    return df.tail(count)  # 只返回最近的count条数据
                else:
                    print("获取Tick数据失败：无数据返回")
                    return None
            else:
                # 返回模拟数据
                print(f"无法获取真实数据：{'API未连接' if not self.api_connected else 'RQData不可用'}")
                return None
        except Exception as e:
            print(f"获取Tick数据失败：{e}")
            return None
    
    def get_contract_info(self, symbol: str) -> Optional[Dict]:
        """获取合约信息"""
        try:
            if RQDATA_AVAILABLE and self.api_connected:
                # 转换合约代码为RQData格式
                rq_symbol = self._convert_symbol(symbol)
                print(f"使用RQData格式合约代码: {rq_symbol}")
                
                # 使用RQData获取合约信息
                instrument = rqd.instruments(rq_symbol)
                
                if instrument:
                    return {
                        'symbol': symbol,
                        'name': instrument[0].name,
                        'exchange': instrument[0].exchange,
                        'product': instrument[0].underlying_symbol,
                        'price_tick': instrument[0].price_tick,
                        'volume_multiple': instrument[0].contract_multiplier,
                        'margin_rate': instrument[0].margin_rate,
                        'expire_datetime': instrument[0].maturity_date,
                        'create_datetime': instrument[0].listed_date
                    }
                else:
                    print("获取合约信息失败：合约不存在")
                    return None
            else:
                # 返回模拟数据
                print(f"无法获取真实数据：{'API未连接' if not self.api_connected else 'RQData不可用'}")
                return None
        except Exception as e:
            print(f"获取合约信息失败：{e}")
            return None
    
    def get_market_data(self, symbols: List[str]) -> Dict[str, Dict]:
        """批量获取市场数据"""
        market_data = {}
        
        for symbol in symbols:
            try:
                if RQDATA_AVAILABLE and self.api_connected:
                    # 转换合约代码为RQData格式
                    rq_symbol = self._convert_symbol(symbol)
                    print(f"使用RQData格式合约代码: {rq_symbol}")
                    
                    # 使用RQData获取最新行情数据
                    quote = rqd.get_quote(rq_symbol)
                    
                    if not quote.empty:
                        market_data[symbol] = {
                            'latest_price': quote['last'].iloc[0],
                            'open': quote['open'].iloc[0],
                            'high': quote['high'].iloc[0],
                            'low': quote['low'].iloc[0],
                            'pre_close': quote['prev_close'].iloc[0],
                            'volume': quote['volume'].iloc[0],
                            'open_interest': quote['open_interest'].iloc[0],
                            'bid_price1': quote['bid1'].iloc[0],
                            'ask_price1': quote['ask1'].iloc[0]
                        }
                    else:
                        print(f"获取{symbol}市场数据失败：无数据返回")
                        market_data[symbol] = {
                            'latest_price': 0,
                            'open': 0,
                            'high': 0,
                            'low': 0,
                            'pre_close': 0,
                            'volume': 0,
                            'open_interest': 0,
                            'bid_price1': 0,
                            'ask_price1': 0
                        }
                else:
                    # 模拟数据
                    market_data[symbol] = {
                        'latest_price': 0,
                        'open': 0,
                        'high': 0,
                        'low': 0,
                        'pre_close': 0,
                        'volume': 0,
                        'open_interest': 0,
                        'bid_price1': 0,
                        'ask_price1': 0
                    }
            except Exception as e:
                print(f"获取{symbol}市场数据失败：{e}")
                market_data[symbol] = {
                    'latest_price': 0,
                    'open': 0,
                    'high': 0,
                    'low': 0,
                    'pre_close': 0,
                    'volume': 0,
                    'open_interest': 0,
                    'bid_price1': 0,
                    'ask_price1': 0
                }
        
        return market_data
    
    def get_all_symbols(self) -> List[str]:
        """获取所有品种列表
        
        Returns:
            List[str]: 所有品种的合约代码列表
        """
        try:
            # 直接使用本地枚举数据，不使用RQData获取
            print("使用本地枚举品种列表")
            # 从get_all_symbols_by_exchange获取所有品种
            from qihuo_analyzer.data.data_fetcher import DataFetcher
            data_fetcher = DataFetcher()
            symbols_by_exchange = data_fetcher.get_all_symbols_by_exchange()
            symbols = []
            for exchange, products in symbols_by_exchange.items():
                for product, product_data in products.items():
                    # 使用每个品种的第一个合约作为代表
                    if product_data['contracts']:
                        symbols.append(product_data['contracts'][0])
            return symbols
        except Exception as e:
            print(f"获取所有品种列表失败：{e}")
            # 返回模拟数据
            return [
                "CU2603", "AL2603", "ZN2603", "PB2603", "NI2603", "SN2603",
                "AU2603", "AG2603", "RB2603", "HC2603", "BU2603", "RU2603",
                "SC2603", "I2603", "J2603", "JM2603", "A2603", "M2603",
                "Y2603", "P2603", "C2603", "CS2603", "L2603", "V2603",
                "PP2603", "TA2603", "CF2603", "SR2603", "MA2603", "FG2603"
            ]
