# coding:utf-8

import pandas as pd
from sqlalchemy import create_engine, text
from datetime import datetime
import redis
import json
import sys
import os

# 添加项目根目录到路径，便于导入config
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_root)

# 读取配置
try:
    from src.valuation_analysis.config import REDIS_CONFIG
except ImportError:
    REDIS_CONFIG = {
        'host': 'localhost',
        'port': 6379,
        'db': 0,
        'password': None
    }

REDIS_KEY = 'xq_stock_changes_latest'  # Redis中存放行情的主键

def get_redis_conn():
    """获取Redis连接"""
    pool = redis.ConnectionPool(
        host=REDIS_CONFIG['host'],
        port=REDIS_CONFIG['port'],
        db=REDIS_CONFIG.get('db', 0),
        password=REDIS_CONFIG.get('password', None),
        decode_responses=True
    )
    return redis.Redis(connection_pool=pool)

def fetch_stock_data_from_redis():
    """从Redis获取股票数据"""
    try:
        r = get_redis_conn()
        
        # 从Redis获取所有股票数据
        all_stock_data = r.hgetall(REDIS_KEY)
        
        if not all_stock_data:
            print("Redis中没有找到股票数据")
            return pd.DataFrame()
        
        # 转换为DataFrame
        stock_list = []
        for symbol, value in all_stock_data.items():
            try:
                stock_data = json.loads(value)
                stock_list.append(stock_data)
            except json.JSONDecodeError:
                print(f"解析股票数据失败: {symbol}")
                continue
        
        if stock_list:
            df = pd.DataFrame(stock_list)
            print(f"从Redis成功获取 {len(df)} 条股票数据")
            return df
    else:
            print("Redis数据解析失败")
            return pd.DataFrame()
            
    except Exception as e:
        print(f"从Redis获取数据时发生错误: {str(e)}")
        return pd.DataFrame()

def get_cache_mark():
    """获取当前时间对应的缓存标记（0m, 2m, 4m, 6m, 8m）"""
    current_minute = datetime.now().minute
    mark = (current_minute % 10) // 2 * 2  # 将分钟数转换为0,2,4,6,8
    return "{}m".format(mark)

def save_sector_cache(engine, df_result, cache_mark):
    """保存板块数据到缓存表"""
    try:
        # 复制数据并添加缓存标记
        df_cache = df_result.copy()
        df_cache['cache_mark'] = cache_mark
        
        # 删除旧的缓存数据
        delete_query = text("DELETE FROM sector_performance_cache WHERE cache_mark = :cache_mark")
        with engine.connect() as conn:  # 使用 connect() 创建连接
            conn.execute(delete_query, {'cache_mark': cache_mark})
            conn.commit()  # 提交事务
        
        # 保存新的缓存数据
        df_cache.to_sql('sector_performance_cache', con=engine, if_exists='append', index=False)
        print("缓存数据已保存，标记: {}".format(cache_mark))
    except Exception as e:
        print("保存缓存数据时发生错误: {}".format(str(e)))

def ensure_cache_table_exists(engine):
    """确保缓存表存在"""
    try:
        create_table_query = text("""
            CREATE TABLE IF NOT EXISTS sector_performance_cache (
                id INT AUTO_INCREMENT PRIMARY KEY,
                sector_name VARCHAR(100),
                up_count INT,
                total_count INT,
                ratio FLOAT,
                rank_num INT,
                rank_change INT,
                add_time DATETIME,
                cache_mark VARCHAR(10)
            )
        """)
        with engine.connect() as conn:  # 使用 connect() 创建连接
            conn.execute(create_table_query)
            conn.commit()  # 提交事务
        print("缓存表检查/创建完成")
    except Exception as e:
        print("创建缓存表时发生错误: {}".format(str(e)))

def get_previous_cache_marks():
    """获取缓存标记的对应关系"""
    return {
        0: 4,  # 0m 对比 4m的数据
        2: 6,  # 2m 对比 6m的数据
        4: 8,  # 4m 对比 8m的数据
        6: 0,  # 6m 对比 0m的数据
        8: 2   # 8m 对比 2m的数据
    }

def get_previous_cache_ranks(engine):
    """获取上一个时间点的缓存数据"""
    try:
        # 获取当前缓存标记
        current_mark = int(get_cache_mark().replace('m', ''))
        
        # 获取应该对比的缓存标记
        cache_marks = get_previous_cache_marks()
        previous_mark = cache_marks.get(current_mark)
        
        if previous_mark is None:
            print("无法确定对比的缓存标记")
            return {}
            
        previous_cache_mark = "{}m".format(previous_mark)
        print("当前时间标记: {}m, 对比的缓存标记: {}".format(current_mark, previous_cache_mark))
        
        query = text("""
            SELECT sector_name, rank_num
            FROM sector_performance_cache
            WHERE cache_mark = :cache_mark
        """)
        
        result = pd.read_sql_query(query, engine, params={'cache_mark': previous_cache_mark})
        if result.empty:
            print("未找到缓存标记 {} 的数据".format(previous_cache_mark))
            return {}
            
        return dict(zip(result['sector_name'], result['rank_num']))
    except Exception as e:
        print("获取缓存数据时发生错误: {}".format(str(e)))
        return {}

def calculate_rank_change(row, previous_ranks):
    """计算排名变化"""
    previous_rank = previous_ranks.get(row['sector_name'])
    if previous_rank is None:
        return 0
    return previous_rank - row['rank_num']

def get_high_performance_stocks(db_url):
    """获取涨幅超过1.5%的股票及其板块分布情况"""
    engine = create_engine(db_url)

    try:
        # 确保缓存表存在
        ensure_cache_table_exists(engine)

        # 从Redis获取股票数据
        print("从Redis获取股票数据...")
        stock_changes_df = fetch_stock_data_from_redis()
        
        if stock_changes_df.empty:
            print("Redis数据获取失败，无法进行分析")
            return []

        print(f"Redis数据获取成功，共 {len(stock_changes_df)} 条记录")
        
        # 读取板块信息
        gp_gnbk_df = pd.read_sql_table('gp_gnbk', con=engine)

        # 处理symbol字段 - 根据Redis数据格式，symbol已经是完整格式（如SZ002916）
        if 'symbol' in stock_changes_df.columns:
            # 保持原始格式用于关联板块表，因为板块表使用的是完整格式（如SZ000973）
            stock_changes_df['symbol_clean'] = stock_changes_df['symbol']
        else:
            print("股票数据中缺少symbol字段")
            return []

        # 筛选涨幅超过 1.5% 的股票
        high_performance_stocks = stock_changes_df[stock_changes_df['percent'] > 1.5]
        print(f"筛选结果: {len(high_performance_stocks)} 只股票涨幅超过1.5%")
        
        if len(high_performance_stocks) == 0:
            print("没有股票涨幅超过1.5%，尝试降低阈值到0.5%...")
            high_performance_stocks = stock_changes_df[stock_changes_df['percent'] > 0.5]
            print(f"筛选结果: {len(high_performance_stocks)} 只股票涨幅超过0.5%")
            
            if len(high_performance_stocks) == 0:
                print("仍然没有股票涨幅超过0.5%，尝试获取所有上涨股票...")
                high_performance_stocks = stock_changes_df[stock_changes_df['percent'] > 0]
                print(f"筛选结果: {len(high_performance_stocks)} 只股票上涨")

        # 关联两个表，获取 bk_name
        merged_df = high_performance_stocks.merge(gp_gnbk_df, left_on='symbol_clean', right_on='gp_code')

        # 统计每个 bk_name 的数量
        total_counts = gp_gnbk_df['bk_name'].value_counts()
        high_performance_counts = merged_df['bk_name'].value_counts()

        # 计算每个板块的上涨家数及占比
        result = []
        for bk_name, count in high_performance_counts.items():
            total_count = total_counts[bk_name]
            ratio = count / total_count
            result.append((bk_name, count, total_count, ratio))

        # 按比重排序
        result.sort(key=lambda x: x[3], reverse=True)

        # 创建DataFrame并添加排序字段
        df_result = pd.DataFrame(result, columns=['sector_name', 'up_count', 'total_count', 'ratio'])
        df_result['rank_num'] = range(1, len(df_result) + 1)  # 添加排序字段，从1开始
        current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        df_result['add_time'] = current_time  # 添加时间字段

        # 获取上一个时间点的缓存数据进行对比
        previous_ranks = get_previous_cache_ranks(engine)
        # 计算排名变化
        df_result['rank_change'] = df_result.apply(
            lambda row: calculate_rank_change(row, previous_ranks), axis=1
        )

        # 保存到数据库（追加模式）
        df_result.to_sql('sector_performance', con=engine, if_exists='append', index=False)

        # 保存到缓存表
        cache_mark = get_cache_mark()
        save_sector_cache(engine, df_result, cache_mark)

        # 输出结果
        print("\n板块分析结果:")
        for _, row in df_result.iterrows():
            print("板块名称: {}, 上涨家数: {}, 总数: {}, 比重: {:.2%}, 排名: {}, 排名变化: {}".format(
                row['sector_name'], row['up_count'], row['total_count'],
                row['ratio'], row['rank_num'], row['rank_change']
            ))
            
        return result
    except Exception as e:
        print("分析数据时发生错误: {}".format(str(e)))
        return []

def get_top_industries_and_stocks(db_url, top_start=1, top_end=10):
    """
    分析在多个热门板块中出现的股票

    Parameters:
    -----------
    db_url : str
        数据库连接URL
    top_start : int
        起始排名
    top_end : int
        结束排名
    """
    try:
        engine = create_engine(db_url)

        # 获取高表现股票及其板块信息
        top_industries = get_high_performance_stocks(db_url)
        if not top_industries:
            print("无法获取行业数据")
            return

        # 提取指定范围的行名称
        top_industry_names = [industry[0] for industry in top_industries[top_start-1:top_end]]

        # 从Redis获取股票数据
        stock_changes_df = fetch_stock_data_from_redis()
        if stock_changes_df.empty:
            print("无法获取股票数据")
            return
            
        # 读取板块信息
        gp_gnbk_df = pd.read_sql_table('gp_gnbk', con=engine)

        # 处理symbol字段
        if 'symbol' in stock_changes_df.columns:
            # 保持原始格式用于关联板块表
            stock_changes_df['symbol_clean'] = stock_changes_df['symbol']
        else:
            print("股票数据中缺少symbol字段")
            return

        # 关联两个表，获取 bk_name 和 gp_name
        merged_df = stock_changes_df.merge(gp_gnbk_df, left_on='symbol_clean', right_on='gp_code')

        # 筛选指定范围的行业的股票
        filtered_df = merged_df[merged_df['bk_name'].isin(top_industry_names)]

        # 统计每只股票命中行业的数量
        stock_industry_counts = filtered_df.groupby(['symbol', 'name'])['bk_name'].nunique().sort_values(ascending=False).head(10)

        # 获取每只股票的命中行业数量
        stock_industry_list = stock_industry_counts.reset_index()
        stock_industry_list.columns = ['symbol', 'stock_name', 'sector_count']
        current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        stock_industry_list['add_time'] = current_time  # 添加时间字段

        # 保存结果到数据库（改为追加模式）
        stock_industry_list.to_sql('top_sector_stocks', con=engine, if_exists='append', index=False)

        # 输出结果
        for index, row in stock_industry_list.iterrows():
            print("股票代码: {}, 股票名称: {}, 命中行业数量: {}".format(
                row['symbol'], row['stock_name'], row['sector_count']
            ))

    except Exception as e:
        print("分析行业数据时发生错误: {}".format(str(e)))

def clean_historical_data(engine):
    """清理当天0点之前的历史数据"""
    try:
        today = datetime.now().strftime('%Y-%m-%d 00:00:00')
        
        # 清理sector_performance表
        clean_performance_query = text("""
            DELETE FROM sector_performance 
            WHERE add_time < :today
        """)
        
        # 清理sector_performance_cache表
        clean_cache_query = text("""
            DELETE FROM sector_performance_cache 
            WHERE add_time < :today
        """)
        
        # 清理top_sector_stocks表
        clean_stocks_query = text("""
            DELETE FROM top_sector_stocks 
            WHERE add_time < :today
        """)
        
        with engine.connect() as conn:  # 使用 connect() 创建连接
            result1 = conn.execute(clean_performance_query, {'today': today})
            result2 = conn.execute(clean_cache_query, {'today': today})
            result3 = conn.execute(clean_stocks_query, {'today': today})
            conn.commit()  # 提交事务
            
        print("清理历史数据完成:")
        print("- sector_performance表删除了{}条记录".format(result1.rowcount))
        print("- sector_performance_cache表删除了{}条记录".format(result2.rowcount))
        print("- top_sector_stocks表删除了{}条记录".format(result3.rowcount))
        
    except Exception as e:
        print("清理历史数据时发生错误: {}".format(str(e)))

if __name__ == "__main__":
    # 示例调用
    db_url = 'mysql+pymysql://root:Chlry#$.8@192.168.18.199:3306/db_gp_cj'
    
    # 创建数据库连接
    engine = create_engine(db_url)
    
    # 清理历史数据
    clean_historical_data(engine)
    
    # 执行主要分析 - 完全使用Redis数据源
    print("=" * 60)
    print("板块分析脚本启动 - Redis数据源版本")
    print("=" * 60)
    print("使用Redis作为数据源")
    print("确保batch_stock_price_collector.py脚本正在运行")
    print("-" * 60)
    
    # 执行分析
    get_top_industries_and_stocks(db_url, 1, 10)
    
    print("=" * 60)
    print("板块分析完成")
    print("=" * 60)