"""KPI计算引擎 v4 — 基于会计科目余额和销售报表"""
import httpx, asyncio, os
from datetime import datetime
from app.database import get_session_local
from app.models import KPIDefinition, KPIValue

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

async def _get(url: str, params: dict = None):
    async with httpx.AsyncClient(timeout=20) as c:
        r = await c.get(url, headers={"X-API-Key": ERP_KEY}, params=params)
        return r.json()

async def calculate_all():
    db = get_session_local()()
    try:
        now = datetime.now()
        period = f"{now.year}-{now.month:02d}"
        
        # 1. 从科目余额表取数据（BalanceInfo）
        balance_data = await _get(f"{ERP_API}/api/v1/query", {"table": "BalanceInfo", "limit": 200})
        balances = balance_data.get("data", [])
        
        # 按科目和期间汇总
        revenue = 0      # 营业收入 (Act_ID=4)
        cost = 0         # 营业成本 (Act_ID=5)
        ar_balance = 0   # 应收账款 (Act_ID=3)
        inv_balance = 0  # 库存商品 (Act_ID=2)
        
        for b in balances:
            aid = b.get("Act_ID")
            tot = float(b.get("Act_Tot", 0) or 0)
            hap = float(b.get("Act_Hap", 0) or 0)
            if aid == 4:       # 营业收入（本期发生额更准确）
                revenue += hap if hap > 0 else tot
            elif aid == 5:     # 营业成本
                cost += hap if hap > 0 else tot
            elif aid == 3:     # 应收账款余额
                ar_balance = tot
            elif aid == 2:     # 存货余额
                inv_balance = tot
        
        # 2. 从销售总览取数据
        summary = await _get(f"{ERP_API}/api/v1/stats/sales-summary", {"year": now.year})
        s = summary.get("summary", {})
        total_sales = s.get("total_amount", 0)
        total_customers = s.get("customer_count", 0)
        
        # 3. 前5客户集中度
        top_customers = await _get(f"{ERP_API}/api/v1/stats/customer-top", {"year": now.year, "limit": 5})
        top5_amt = sum(c["amount"] for c in top_customers.get("data", []))
        top5_ratio = round(top5_amt / total_sales * 100, 1) if total_sales > 0 else 0
        
        # 4. 计算KPI
        gross_margin = round((revenue - cost) / revenue * 100, 2) if revenue > 0 else 0
        ar_turnover = round(revenue / ar_balance, 2) if ar_balance > 0 else 0
        inv_turnover = round(cost / inv_balance, 2) if inv_balance > 0 else 0
        
        kpi_values = {
            "SALES_TOTAL": total_sales,
            "CUSTOMER_COUNT": total_customers,
            "SALES_PROFIT_RATE": gross_margin,
            "RECEIVABLE_TURNOVER": ar_turnover,
            "TURNOVER_RATE": inv_turnover,
            "TOP5_CUSTOMER_RATIO": top5_ratio,
        }
        
        for code, value in kpi_values.items():
            kpi = db.query(KPIDefinition).filter(KPIDefinition.kpi_code == code).first()
            if kpi and (value > 0 or kpi.kpi_code in ("SALES_PROFIT_RATE","RECEIVABLE_TURNOVER","TURNOVER_RATE")):
                existing = db.query(KPIValue).filter(
                    KPIValue.kpi_id == kpi.id,
                    KPIValue.period == period,
                    KPIValue.source_type == "erp",
                ).first()
                if not existing:
                    kv = KPIValue(kpi_id=kpi.id, period=period, actual_value=round(value, 2), source_type="erp", data_status="verified")
                    db.add(kv)
        
        db.commit()
        print(f"✅ KPI计算完成: {period}")
        for code, value in kpi_values.items():
            kpi_n = db.query(KPIDefinition).filter(KPIDefinition.kpi_code == code).first()
            n = kpi_n.kpi_name if kpi_n else code
            print(f"  {n}: {round(value,2) if value else '-'}")
    except Exception as e:
        print(f"❌ KPI计算失败: {e}")
    finally:
        db.close()

if __name__ == "__main__":
    asyncio.run(calculate_all())
