#!/usr/bin/env python3
"""advice_reconciliation.py — 建议对账脚本

每周运行一次，对比 decisions.json 的 advice_timeline 与 portfolio.json
的实际持仓变化，统计准确率。

用法：
  python3 advice_reconciliation.py          # 正常对账
  python3 advice_reconciliation.py --force  # 强制重新对账所有建议
"""
import json
import sys
from datetime import datetime, timedelta
from pathlib import Path

DATA_DIR = Path(__file__).parent / "data"
DECISIONS_PATH = DATA_DIR / "decisions.json"
PORTFOLIO_PATH = DATA_DIR / "portfolio.json"
ACCURACY_PATH = DATA_DIR / "accuracy_stats.json"

def load_json(path, default=None):
    try:
        with open(path, encoding="utf-8") as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return {} if default is None else default

def save_json(path, data):
    Path(path).parent.mkdir(parents=True, exist_ok=True)
    with open(path, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def get_holding_change(portfolio, code):
    """获取某只股票的当前持仓信息"""
    holdings = portfolio.get("holdings", [])
    for h in holdings:
        if h["code"] == code:
            return {
                "code": code,
                "name": h.get("name", ""),
                "shares": h.get("shares", 0),
                "cost": h.get("cost", 0),
                "price": h.get("price", 0),
                "position_pct": h.get("position_pct", 0),
            }
    return None  # 已清仓

def evaluate_advice(advice, current_holding):
    """评估一条建议是否正确

    Returns: 'correct', 'partial', 'wrong', 'pending', 'unknown'
    """
    direction = advice.get("direction", "")
    status = advice.get("status", "pending")

    if status == "ignored":
        return "ignored"
    if status == "pending":
        return "pending"

    if not current_holding:
        # 股票已清仓
        if direction in ("卖出", "清仓", "减仓"):
            return "correct"
        elif direction in ("买入", "加仓", "补仓"):
            return "wrong"
        else:
            return "unknown"

    shares = current_holding.get("shares", 0)
    cost = current_holding.get("cost", 0)
    price = current_holding.get("price", 0)
    pnl_pct = (price - cost) / cost * 100 if cost > 0 else 0

    if direction in ("买入", "加仓", "补仓"):
        # 如果建议买入时价格低于现价，或浮盈为正 → 正确
        try:
            advised_price = float(advice.get("price", 0))
            if advised_price > 0 and price > 0:
                if price >= advised_price * 0.95:  # 允许5%误差
                    return "correct"
                else:
                    return "wrong"
            else:
                return "unknown"
        except:
            return "unknown"

    elif direction in ("卖出", "清仓", "减仓"):
        # 如果建议卖出时价格高于现价 → 正确（规避了下跌）
        try:
            advised_price = float(advice.get("price", 0))
            if advised_price > 0 and price > 0:
                if price <= advised_price * 1.05:
                    return "correct"
                else:
                    return "wrong"
            else:
                return "unknown"
        except:
            return "unknown"

    elif direction in ("持有", "观望"):
        # 持有建议 → 看后续是否涨
        try:
            advised_price = float(advice.get("price", 0))
            if advised_price > 0 and price > 0:
                change = (price - advised_price) / advised_price * 100
                if change > -5:  # 没跌超过5%
                    return "correct"
                else:
                    return "wrong"
            else:
                return "unknown"
        except:
            return "unknown"

    elif direction == "自选":
        # 自选建议无法直接对账
        return "unknown"

    return "unknown"


def run():
    force = "--force" in sys.argv

    decisions = load_json(DECISIONS_PATH, {"decisions": []})
    portfolio = load_json(PORTFOLIO_PATH, {"holdings": []})
    old_stats = load_json(ACCURACY_PATH, {})

    results = []
    total = {"correct": 0, "wrong": 0, "partial": 0, "unknown": 0, "pending": 0, "ignored": 0}

    for entry in decisions.get("decisions", []):
        code = entry["code"]
        name = entry.get("name", code)
        timeline = entry.get("advice_timeline", [])

        if not timeline:
            continue

        current_holding = get_holding_change(portfolio, code)

        for i, advice in enumerate(timeline):
            # 跳过已评估过的（除非 --force）
            if not force and advice.get("evaluated"):
                # 计数已有结果
                result = advice.get("result", "unknown")
                total[result] = total.get(result, 0) + 1
                continue

            result = evaluate_advice(advice, current_holding)
            advice["evaluated"] = True
            advice["result"] = result
            advice["evaluated_at"] = datetime.now().isoformat()
            total[result] = total.get(result, 0) + 1

            results.append({
                "code": code,
                "name": name,
                "date": advice.get("date", ""),
                "direction": advice.get("direction", ""),
                "summary": advice.get("summary", ""),
                "result": result,
            })

    # 保存更新后的 decisions.json（含评估标记）
    save_json(DECISIONS_PATH, decisions)

    # 计算准确率
    evaluated = total["correct"] + total["wrong"] + total["partial"]
    accuracy = round(total["correct"] / evaluated * 100, 1) if evaluated > 0 else 0

    stats = {
        "updated_at": datetime.now().isoformat(),
        "period_start": old_stats.get("period_start", (datetime.now() - timedelta(days=7)).isoformat()),
        "period_end": datetime.now().isoformat(),
        "total_advice": sum(total.values()),
        "correct": total["correct"],
        "wrong": total["wrong"],
        "partial": total["partial"],
        "unknown": total["unknown"],
        "pending": total["pending"],
        "ignored": total["ignored"],
        "evaluated": evaluated,
        "accuracy_pct": accuracy,
        "details": results,
        # 累计统计
        "cumulative": {
            "total": old_stats.get("cumulative", {}).get("total", 0) + evaluated,
            "correct": old_stats.get("cumulative", {}).get("correct", 0) + total["correct"],
            "wrong": old_stats.get("cumulative", {}).get("wrong", 0) + total["wrong"],
        },
    }

    cum = stats["cumulative"]
    cum_accuracy = round(cum["correct"] / cum["total"] * 100, 1) if cum["total"] > 0 else 0
    stats["cumulative_accuracy_pct"] = cum_accuracy

    save_json(ACCURACY_PATH, stats)

    # 输出摘要
    print(f"📊 建议对账报告")
    print(f"  周期: {stats['period_start'][:10]} ~ {stats['period_end'][:10]}")
    print(f"  总建议: {stats['total_advice']}")
    print(f"  ✅ 正确: {stats['correct']}")
    print(f"  ❌ 错误: {stats['wrong']}")
    print(f"  ⏳ 待确认: {stats['pending']}")
    print(f"  ✗ 已忽略: {stats['ignored']}")
    print(f"  ❓ 无法判断: {stats['unknown']}")
    print(f"  📈 本期准确率: {accuracy}%")
    print(f"  📈 累计准确率: {cum_accuracy}%")

    if results:
        print(f"\n  详情:")
        for r in results[:20]:
            icon = {"correct": "✅", "wrong": "❌", "partial": "🟡", "unknown": "❓", "pending": "⏳", "ignored": "✗"}
            print(f"    {icon.get(r['result'], '?')} {r['name']}({r['code']}) {r['direction']} → {r['result']}")


if __name__ == "__main__":
    run()
