"""成本分析引擎 — 管理会计OS
标准成本vs实际成本差异分析（量差/价差/效率差异）
ABC作业成本法分配
"""
import logging, os
from datetime import datetime
from typing import Optional, List, Dict
from app.database import get_session_local
from app.models import StandardCost, ActualCost, AbcActivity, AbcAllocation, KPIDefinition, KPIValue

logger = logging.getLogger("cma.cost")

ERP_API = "http://127.0.0.1:8300"
ERP_KEY = os.environ.get("ERP_API_KEY", "erp-gateway-key-bhwl-2026")


# ============================================================
# 差异计算
# ============================================================

def calc_variance(standard_qty: float, actual_qty: float,
                  standard_price: float, actual_price: float) -> dict:
    """计算量差和价差

    量差 = (实际用量 - 标准用量) × 标准价格
    价差 = (实际价格 - 标准价格) × 实际用量
    总差异 = 量差 + 价差
    """
    qty_variance = round((actual_qty - standard_qty) * standard_price, 2)
    price_variance = round((actual_price - standard_price) * actual_qty, 2)
    total_variance = round(qty_variance + price_variance, 2)
    return {
        "qty_variance": qty_variance,       # 量差
        "price_variance": price_variance,     # 价差
        "total_variance": total_variance,     # 总差异
        "standard_cost": round(standard_qty * standard_price, 2),
        "actual_cost": round(actual_qty * actual_price, 2),
    }


def calc_efficiency_variance(standard_hours: float, actual_hours: float,
                             standard_rate: float) -> dict:
    """计算效率差异（人工/制造费用）

    效率差异 = (实际工时 - 标准工时) × 标准分配率
    分配率差异 = (实际分配率 - 标准分配率) × 实际工时
    """
    eff = round((actual_hours - standard_hours) * standard_rate, 2)
    # 假设实际分配率从外面传入
    return {
        "efficiency_variance": eff,
    }


# ============================================================
# 产品级差异分析
# ============================================================

def calc_product_variance(product_code: str, period: str) -> dict:
    """计算指定产品在指定期间的成本差异"""
    db = get_session_local()()
    try:
        standards = db.query(StandardCost).filter(
            StandardCost.product_code == product_code,
            StandardCost.status == "active",
        ).all()
        actuals = db.query(ActualCost).filter(
            ActualCost.product_code == product_code,
            ActualCost.period == period,
        ).all()

        if not standards or not actuals:
            return {"product_code": product_code, "error": "标准成本或实际成本数据不足", "items": [], "summary": {}}

        # 按 cost_type 分组
        cost_types = set()
        for s in standards: cost_types.add(s.cost_type)
        for a in actuals: cost_types.add(a.cost_type)

        items = []
        total_std = 0
        total_act = 0
        total_qty_var = 0
        total_price_var = 0

        for ct in sorted(cost_types):
            std_items = [s for s in standards if s.cost_type == ct]
            act_items = [a for a in actuals if a.cost_type == ct]

            if std_items and act_items:
                s = std_items[0]
                a = act_items[0]
                var = calc_variance(s.standard_quantity, a.actual_quantity,
                                    s.standard_price, a.actual_price)
                items.append({
                    "cost_type": ct,
                    "item_name": s.item_name,
                    "standard_quantity": s.standard_quantity,
                    "actual_quantity": a.actual_quantity,
                    "standard_price": s.standard_price,
                    "actual_price": a.actual_price,
                    "standard_cost": var["standard_cost"],
                    "actual_cost": var["actual_cost"],
                    "qty_variance": var["qty_variance"],
                    "price_variance": var["price_variance"],
                    "total_variance": var["total_variance"],
                })
                total_std += var["standard_cost"]
                total_act += var["actual_cost"]
                total_qty_var += var["qty_variance"]
                total_price_var += var["price_variance"]

        return {
            "product_code": product_code,
            "period": period,
            "items": items,
            "summary": {
                "total_standard_cost": round(total_std, 2),
                "total_actual_cost": round(total_act, 2),
                "total_variance": round(total_act - total_std, 2),
                "total_qty_variance": round(total_qty_var, 2),
                "total_price_variance": round(total_price_var, 2),
                "variance_rate": round((total_act - total_std) / total_std * 100, 2) if total_std else 0,
            }
        }
    finally:
        db.close()


# ============================================================
# ABC 作业成本分配
# ============================================================

def calc_driver_rate(activity_id: int) -> dict:
    """计算作业动因分配率 = 总成本 / 动因总量"""
    db = get_session_local()()
    try:
        act = db.query(AbcActivity).filter(AbcActivity.id == activity_id).first()
        if not act or not act.driver_volume:
            return {"error": "作业中心不存在或动因总量为0"}
        rate = round(act.total_cost / act.driver_volume, 4) if act.driver_volume > 0 else 0
        act.driver_rate = rate
        db.commit()
        return {
            "activity_code": act.activity_code,
            "activity_name": act.activity_name,
            "total_cost": act.total_cost,
            "driver_volume": act.driver_volume,
            "driver_rate": rate,
        }
    finally:
        db.close()


def allocate_cost(activity_id: int, period: str, product_code: str,
                  product_name: str, driver_consumed: float) -> dict:
    """按动因分配成本到产品"""
    db = get_session_local()()
    try:
        act = db.query(AbcActivity).filter(AbcActivity.id == activity_id).first()
        if not act or act.driver_rate == 0:
            # 自动计算分配率
            if act and act.driver_volume > 0:
                act.driver_rate = round(act.total_cost / act.driver_volume, 4)
                db.commit()
        if not act or act.driver_rate == 0:
            return {"error": "分配率未设置"}
        allocated = round(driver_consumed * act.driver_rate, 2)
        alloc = AbcAllocation(
            period=period,
            activity_id=activity_id,
            product_code=product_code,
            product_name=product_name,
            driver_consumed=driver_consumed,
            allocated_cost=allocated,
        )
        db.add(alloc)
        db.commit()
        return {
            "activity_code": act.activity_code,
            "product_code": product_code,
            "driver_consumed": driver_consumed,
            "driver_rate": act.driver_rate,
            "allocated_cost": allocated,
        }
    finally:
        db.close()


# ============================================================
# 成本总览数据
# ============================================================

def get_cost_overview(period: str) -> dict:
    """获取成本总览数据（总成本、结构占比、趋势）"""
    db = get_session_local()()
    try:
        # 从实际成本表汇总
        actual_costs = db.query(ActualCost).filter(ActualCost.period == period).all()
        total_cost = sum(a.actual_cost for a in actual_costs)

        # 按成本类型分组
        by_type: Dict[str, float] = {}
        for a in actual_costs:
            by_type[a.cost_type] = by_type.get(a.cost_type, 0) + a.actual_cost

        structure = [
            {"cost_type": k, "amount": round(v, 2), "ratio": round(v / total_cost * 100, 1) if total_cost else 0}
            for k, v in sorted(by_type.items())
        ]

        # 从ERP获取成本数据做补充
        import httpx
        try:
            resp = httpx.get(f"{ERP_API}/api/v1/query", params={"table": "BalanceInfo", "limit": 100},
                             headers={"X-API-Key": ERP_KEY}, timeout=10)
            balance_data = resp.json().get("data", [])
            erp_cost = 0
            for b in balance_data:
                if b.get("Act_ID") == 5:  # 营业成本
                    erp_cost += float(b.get("Act_Hap", 0) or 0) + float(b.get("Act_Tot", 0) or 0)
        except Exception:
            erp_cost = 0

        # 历史趋势（近6个月）
        from sqlalchemy import text
        year = period[:4]
        months_texts = []
        try:
            m = int(period.split("-")[1])
            for i in range(6):
                pm = m - i
                py = int(year)
                while pm <= 0:
                    pm += 12
                    py -= 1
                months_texts.append(f"{py}-{pm:02d}")

            trend = []
            for p in reversed(months_texts):
                costs = db.query(ActualCost).filter(ActualCost.period == p).all()
                total = round(sum(c.actual_cost for c in costs), 2)
                trend.append({"period": p, "total_cost": total})
        except Exception:
            trend = []

        return {
            "period": period,
            "total_cost": round(total_cost + erp_cost, 2),
            "erp_cost": round(erp_cost, 2),
            "manual_cost": round(total_cost, 2),
            "structure": structure,
            "trend": trend,
        }
    finally:
        db.close()


def get_cost_breakdown(product_code: str, period: str) -> dict:
    """获取成本构成（料/工/费占比）"""
    db = get_session_local()()
    try:
        actuals = db.query(ActualCost).filter(
            ActualCost.product_code == product_code,
            ActualCost.period == period,
        ).all()

        material = sum(a.actual_cost for a in actuals if a.cost_type == "material")
        labor = sum(a.actual_cost for a in actuals if a.cost_type == "labor")
        overhead = sum(a.actual_cost for a in actuals if a.cost_type == "overhead")
        total = material + labor + overhead

        return {
            "product_code": product_code,
            "period": period,
            "material": {"amount": round(material, 2), "ratio": round(material / total * 100, 1) if total else 0},
            "labor": {"amount": round(labor, 2), "ratio": round(labor / total * 100, 1) if total else 0},
            "overhead": {"amount": round(overhead, 2), "ratio": round(overhead / total * 100, 1) if total else 0},
            "total": round(total, 2),
        }
    finally:
        db.close()
