from __future__ import annotations

from collections import Counter
import math
from datetime import datetime, timedelta
from typing import Any

from sentiment_engine import apply_sentiment_to_dashboard


DEMO_LIMITS = [
    ("600664", "哈药股份", 4.94, 10.02, "医药", "创新药+医药流通", "09:25:00", "09:25:00", 0, 5, 11.78, 14.65, 26458),
    ("603580", "艾艾精工", 40.84, 9.99, "机器人", "实控人变更+机器人", "09:25:01", "09:25:01", 0, 3, 0.11, 0.53, 27190),
    ("600785", "新华百货", 9.32, 10.04, "零售", "新零售+股权转让", "10:32:33", "10:32:33", 2, 2, 9.57, 29.44, 4285),
    ("002739", "万达电影", 10.32, 10.02, "文化传媒", "影视院线+AI视频", "09:30:33", "09:30:33", 0, 2, 3.95, 217.94, 25014),
    ("000504", "南华生物", 9.36, 9.99, "医药", "细胞医疗+中报预增", "09:39:18", "09:39:18", 1, 2, 8.73, 30.89, 1962),
    ("000676", "智度股份", 6.22, 10.09, "端侧AI", "AI营销+端侧AI", "09:46:45", "09:46:45", 0, 2, 6.61, 78.36, 10368),
    ("600162", "香江控股", 2.78, 9.88, "房地产", "房地产+地产链", "09:30:57", "09:30:57", 1, 2, 10.56, 90.86, 4540),
    ("002365", "永安药业", 13.18, 10.02, "医药", "医药+宠物经济", "09:33:24", "09:33:24", 0, 2, 10.52, 38.84, 8277),
    ("000566", "海南海药", 5.67, 10.10, "脑机接口", "创新药+脑机接口", "11:01:12", "11:03:48", 2, 2, 22.75, 73.56, 8769),
    ("002632", "道明光学", 9.63, 10.06, "端侧AI", "AI手机+反光材料", "09:25:00", "09:25:00", 0, 1, 2.63, 60.15, 13417),
    ("000892", "欢瑞世纪", 3.87, 9.94, "文化传媒", "短剧+AI应用", "09:34:57", "09:34:57", 0, 1, 10.80, 37.96, 5635),
    ("603496", "恒为科技", 25.08, 10.00, "云计算", "算力+华为", "09:58:12", "10:46:30", 1, 1, 7.65, 80.31, 16611),
    ("603327", "福蓉科技", 8.57, 10.01, "端侧AI", "AI手机+消费电子", "09:30:02", "09:30:02", 0, 1, 7.02, 77.84, 7784),
    ("300968", "格林精密", 10.24, 20.00, "端侧AI", "折叠屏+AI眼镜", "09:36:33", "09:36:33", 0, 1, 20.06, 48.23, 7850),
    ("002045", "国光电器", 8.34, 10.03, "消费电子", "音响电声+AI眼镜", "09:37:45", "09:37:45", 0, 1, 7.11, 66.04, 4517),
    ("600203", "福日电子", 11.92, 9.96, "消费电子", "华为产业链+机器人", "09:45:03", "09:45:03", 0, 1, 12.04, 105.50, 10554),
    ("002881", "美格智能", 39.05, 10.00, "端侧AI", "物理AI+算力模组", "10:07:42", "10:07:42", 0, 1, 14.32, 128.20, 4299),
]


DEMO_BROKEN = [
    ("002141", "贤丰控股", 5.91, 5.35, "PCB板", "PCB板+资产重组", "09:37:03", "14:56:24", 3, 18.95, 61.05),
    ("002432", "九安医疗", 72.00, 7.48, "医药", "业绩增长+AI应用", "10:53:00", "14:09:45", 5, 14.13, 335.00),
    ("002980", "华盛昌", 107.37, 5.12, "光通信", "光通信+仪器仪表", "09:59:18", "14:38:36", 1, 17.94, 108.75),
    ("603725", "天安新材", 14.08, 7.40, "机器人", "机器人+新材料", "09:36:34", "14:37:19", 5, 13.58, 42.92),
    ("603127", "昭衍新药", 53.25, 5.20, "医药", "创新药+CRO", "10:35:49", "10:46:55", 2, 19.56, 335.66),
    ("002261", "拓维信息", 29.95, 6.47, "云计算", "算力+华为", "10:48:15", "10:53:54", 3, 12.04, 343.26),
    ("603893", "瑞芯微", 222.24, 5.58, "国产芯片", "国产芯片+端侧AI", "09:55:26", "13:31:14", 1, 7.60, 939.80),
    ("603103", "横店影视", 14.94, 5.21, "文化传媒", "影视院线+暑期档", "13:01:06", "13:01:51", 1, 2.79, 94.75),
]


DEMO_DOWN = [
    ("603683", "晶华新材", 25.56, -10.00, "新材料", "高位股风险释放", 4.41, 173.67, 1),
    ("603928", "兴业股份", 12.34, -9.99, "化工", "连续上涨后补跌", 11.96, 42.04, 4),
    ("000988", "华工科技", 130.69, -10.00, "光通信", "高位成交放大", 6.28, 1313.42, 1),
    ("603137", "恒尚节能", 32.05, -10.00, "建筑", "昨日涨停断板", 1.48, 58.63, 1),
    ("603115", "海星股份", 81.06, -10.00, "有色金属", "板块退潮", 3.02, 196.08, 1),
    ("605376", "博迁新材", 166.02, -10.00, "新材料", "资金兑现", 5.35, 434.31, 1),
    ("003020", "立方制药", 19.72, -10.00, "医药", "医药分化", 22.88, 45.00, 1),
    ("605255", "天普股份", 78.47, -10.00, "汽车零部件", "连板失败", 2.12, 105.21, 1),
    ("002123", "梦网科技", 7.68, -9.96, "通信", "板块调整", 1.39, 61.86, 2),
    ("603713", "密尔克卫", 64.80, -10.00, "物流", "业绩预期调整", 3.99, 103.43, 1),
]


def _stock_rows() -> list[dict[str, Any]]:
    return [
        {
            "code": code,
            "ts_code": code,
            "name": name,
            "price": price,
            "change": change,
            "sector": sector,
            "reason": reason,
            "first_time": first_time,
            "last_time": last_time,
            "open_times": open_times,
            "streak": streak,
            "turnover_rate": turnover,
            "amount_billion": amount,
            "seal_amount_million": seal,
            "float_mv_billion": round(amount * 3.2, 1),
            "status": "涨停",
        }
        for code, name, price, change, sector, reason, first_time, last_time,
        open_times, streak, turnover, amount, seal in DEMO_LIMITS
    ]


def _broken_rows() -> list[dict[str, Any]]:
    return [
        {
            "code": code,
            "ts_code": code,
            "name": name,
            "price": price,
            "change": change,
            "sector": sector,
            "reason": reason,
            "first_time": first_time,
            "last_time": last_time,
            "open_times": open_times,
            "streak": 1,
            "turnover_rate": turnover,
            "amount_billion": amount,
            "seal_amount_million": 0,
            "float_mv_billion": round(amount * 3.5, 1),
            "status": "炸板",
        }
        for code, name, price, change, sector, reason, first_time, last_time,
        open_times, turnover, amount in DEMO_BROKEN
    ]


def _down_rows() -> list[dict[str, Any]]:
    return [
        {
            "code": code,
            "ts_code": code,
            "name": name,
            "price": price,
            "change": change,
            "sector": sector,
            "reason": reason,
            "first_time": "--",
            "last_time": "--",
            "open_times": 0,
            "streak": streak,
            "turnover_rate": turnover,
            "amount_billion": amount,
            "seal_amount_million": 0,
            "float_mv_billion": round(amount * 4.1, 1),
            "status": "跌停",
        }
        for code, name, price, change, sector, reason, turnover, amount, streak in DEMO_DOWN
    ]


def _ladders(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
    result = []
    for level in sorted({row["streak"] for row in rows}, reverse=True):
        stocks = [row for row in rows if row["streak"] == level]
        result.append(
            {
                "level": level,
                "label": "首板" if level == 1 else f"{level}板",
                "count": len(stocks),
                "stocks": stocks,
            }
        )
    return result


def _sectors(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
    counts = Counter(row["sector"] for row in rows)
    result = []
    for name, count in counts.most_common():
        stocks = [row for row in rows if row["sector"] == name]
        result.append(
            {
                "name": name,
                "count": count,
                "strength": min(99, 48 + count * 9 + max(row["streak"] for row in stocks) * 4),
                "amount_billion": round(sum(row["amount_billion"] for row in stocks), 1),
                "leader": max(stocks, key=lambda row: (row["streak"], row["amount_billion"]))["name"],
                "change": round(sum(row["change"] for row in stocks) / count, 2),
                "max_streak": max(row["streak"] for row in stocks),
            }
        )
    return result


def _yesterday_rows(current: list[dict[str, Any]]) -> list[dict[str, Any]]:
    current_map = {row["code"]: row for row in current}
    definitions = [
        ("600664", "哈药股份", 4, 10.02, "晋级"),
        ("603580", "艾艾精工", 2, 9.99, "晋级"),
        ("600785", "新华百货", 1, 10.04, "晋级"),
        ("002739", "万达电影", 1, 10.02, "晋级"),
        ("000504", "南华生物", 1, 9.99, "晋级"),
        ("000676", "智度股份", 1, 10.09, "晋级"),
        ("603127", "昭衍新药", 1, 5.20, "炸板"),
        ("002432", "九安医疗", 2, 7.48, "炸板"),
        ("001388", "信通电子", 3, -5.33, "断板"),
        ("605255", "天普股份", 2, -10.00, "跌停"),
        ("600403", "大有能源", 1, -6.75, "断板"),
        ("002185", "华天科技", 1, -10.00, "跌停"),
        ("600829", "人民同泰", 1, 2.30, "断板"),
        ("600844", "金煤科技", 1, 1.18, "断板"),
    ]
    rows = []
    for code, name, prior_streak, current_change, outcome in definitions:
        current_row = current_map.get(code, {})
        rows.append(
            {
                "code": code,
                "name": name,
                "prior_streak": prior_streak,
                "current_streak": current_row.get("streak", 0),
                "current_change": current_change,
                "current_price": current_row.get("price", 0),
                "sector": current_row.get("sector", "其他"),
                "reason": current_row.get("reason", "昨日涨停股表现跟踪"),
                "outcome": outcome,
            }
        )
    return rows


def _performance(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
    result = []
    for level in sorted({row["prior_streak"] for row in rows}, reverse=True):
        group = [row for row in rows if row["prior_streak"] == level]
        advanced = sum(row["outcome"] == "晋级" for row in group)
        positive = sum(row["current_change"] > 0 for row in group)
        result.append(
            {
                "level": level,
                "label": "昨日首板" if level == 1 else f"昨日{level}板",
                "count": len(group),
                "advanced": advanced,
                "advance_rate": round(advanced / len(group) * 100, 1),
                "positive_rate": round(positive / len(group) * 100, 1),
                "average_change": round(sum(row["current_change"] for row in group) / len(group), 2),
            }
        )
    return result


def _rotation(sectors: list[dict[str, Any]]) -> list[dict[str, Any]]:
    previous_counts = {
        "端侧AI": 7,
        "医药": 5,
        "文化传媒": 1,
        "消费电子": 1,
        "机器人": 3,
        "房地产": 2,
        "零售": 0,
        "云计算": 2,
        "脑机接口": 1,
    }
    result = []
    for index, sector in enumerate(sectors, start=1):
        previous = previous_counts.get(sector["name"], 0)
        delta = sector["count"] - previous
        result.append(
            {
                **sector,
                "rank": index,
                "previous_count": previous,
                "delta": delta,
                "trend": "升温" if delta > 0 else "降温" if delta < 0 else "持平",
            }
        )
    return result


def build_demo_dashboard(trade_date: str, notice: str = "") -> dict[str, Any]:
    limits = _stock_rows()
    broken = _broken_rows()
    down_limits = _down_rows()
    ladders = _ladders(limits)
    sectors = _sectors(limits)
    yesterday = _yesterday_rows(limits)
    dashboard = {
        "meta": {
            "trade_date": f"{trade_date[:4]}-{trade_date[4:6]}-{trade_date[6:8]}",
            "previous_trade_date": "2026-07-16",
            "source": "demo",
            "updated_at": datetime.now().astimezone().isoformat(timespec="seconds"),
            "notice": notice or "当前展示演示数据，配置 Tushare Token 后可读取真实行情。",
        },
        "overview": {
            "up_count": 2344,
            "down_count": 2695,
            "flat_count": 33,
            "limit_up_count": 41,
            "limit_down_count": 3,
            "broken_count": 25,
            "amount_billion": 24035.6,
            "seal_rate": 62.1,
        },
        "limits": limits,
        "broken": broken,
        "down_limits": down_limits,
        "yesterday_limits": yesterday,
        "limit_performance": _performance(yesterday),
        "ladders": ladders,
        "sectors": sectors,
        "sector_rotation": _rotation(sectors),
    }
    return apply_sentiment_to_dashboard(dashboard)


def build_demo_dragon_tiger(trade_date: str, notice: str = "") -> dict[str, Any]:
    stocks = _stock_rows()[:10]
    seat_names = [
        "机构专用",
        "沪股通专用",
        "深股通专用",
        "中信证券股份有限公司上海分公司",
        "国泰海通证券股份有限公司南京太平南路证券营业部",
    ]
    rows = []
    for index, stock in enumerate(stocks):
        buy = round(86.5 - index * 6.3, 2)
        sell = round(22.8 + index * 3.1, 2)
        net = round(buy - sell, 2)
        institutions = [
            {
                "seat_name": seat_names[index % len(seat_names)],
                "buy_million": buy,
                "sell_million": sell,
                "net_buy_million": net,
            },
            {
                "seat_name": seat_names[(index + 2) % len(seat_names)],
                "buy_million": round(buy * 0.42, 2),
                "sell_million": round(sell * 0.65, 2),
                "net_buy_million": round(buy * 0.42 - sell * 0.65, 2),
            },
        ]
        rows.append(
            {
                "code": stock["code"],
                "ts_code": stock["code"] + (".SH" if stock["code"].startswith("6") else ".SZ"),
                "name": stock["name"],
                "price": stock["price"],
                "change": stock["change"],
                "turnover_rate": stock["turnover_rate"],
                "amount_billion": stock["amount_billion"],
                "buy_million": buy,
                "sell_million": sell,
                "net_buy_million": net,
                "net_rate": round(net / max(buy + sell, 1) * 100, 2),
                "reason": "日涨幅偏离值达到7%" if index % 2 == 0 else "连续三个交易日涨幅偏离值累计达到20%",
                "institutions": institutions,
            }
        )
    return {
        "meta": {
            "trade_date": f"{trade_date[:4]}-{trade_date[4:6]}-{trade_date[6:8]}",
            "source": "demo",
            "updated_at": datetime.now().astimezone().isoformat(timespec="seconds"),
            "notice": notice or "龙虎榜当前展示演示数据。",
        },
        "summary": {
            "stock_count": len(rows),
            "institution_count": sum(len(row["institutions"]) for row in rows),
            "net_buy_million": round(sum(row["net_buy_million"] for row in rows), 2),
            "positive_count": sum(row["net_buy_million"] > 0 for row in rows),
        },
        "rows": rows,
    }


def build_demo_stock_detail(
    code: str,
    trade_date: str,
    name: str = "示例股票",
    industry: str = "其他",
    notice: str = "",
) -> dict[str, Any]:
    end = datetime.strptime(trade_date, "%Y%m%d")
    seed = sum(ord(character) for character in code)
    base = 8 + seed % 45
    prices = []
    close = float(base)
    for index in range(90):
        day = end - timedelta(days=(89 - index))
        drift = math.sin((index + seed) / 6) * 0.018 + 0.002
        open_price = close * (1 + math.sin(index * 1.7) * 0.006)
        close = max(1, close * (1 + drift))
        high = max(open_price, close) * (1.012 + (index % 3) * 0.002)
        low = min(open_price, close) * (0.988 - (index % 2) * 0.002)
        prices.append(
            {
                "trade_date": day.strftime("%Y-%m-%d"),
                "open": round(open_price, 2),
                "high": round(high, 2),
                "low": round(low, 2),
                "close": round(close, 2),
                "change": round((close / open_price - 1) * 100, 2),
                "volume": 180000 + (index % 11) * 26000 + seed * 10,
                "amount_billion": round(1.8 + (index % 9) * 0.36, 2),
            }
        )
    return {
        "meta": {
            "trade_date": f"{trade_date[:4]}-{trade_date[4:6]}-{trade_date[6:8]}",
            "source": "demo",
            "updated_at": datetime.now().astimezone().isoformat(timespec="seconds"),
            "notice": notice or "个股详情当前展示演示数据。",
        },
        "stock": {
            "code": code,
            "ts_code": code + (".SH" if code.startswith("6") else ".SZ"),
            "name": name,
            "industry": industry,
            "area": "--",
            "market": "主板",
            "list_date": "--",
            "price": prices[-1]["close"],
            "change": prices[-1]["change"],
        },
        "prices": prices,
        "moneyflow": {
            "net_million": 18.62,
            "large_million": 31.48,
            "medium_million": -4.12,
            "small_million": -8.74,
        },
    }
