"""Step 3: KPI-SQL生成器
根据KPI的formula定义 + ERP表结构，生成可执行SQL查询
运行: python3 scripts/generate_kpi_sql.py
输出: 打印每个KPI生成的SQL和测试结果

支持SQL Server语法（TOP, GETDATE等）
"""

import sys, os, json, logging, re
from datetime import datetime, timedelta

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app.database import get_engine, get_session_local
from sqlalchemy import text

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("kpi_sql_gen")

# ── KPI → ERP映射规则 ──
# 手工映射关键KPI到ERP表+SQL
# 基于erp_schema实际分析结果

KPI_SQL_MAP = {
    # === 从ERP可获取的数据 ===
    "F_REVENUE_001": {  # 销售总额
        "table": "MasterBill",
        "sql": """SELECT COALESCE(SUM(SumMoney), 0) as value 
FROM MasterBill 
WHERE BillType=1 AND BillState>=3 AND Period=:period""",
        "desc": "销售总额 = 已审核销售单金额之和",
    },
    "F_PROFIT_001": {  # 销售毛利率
        "table": "MasterBill",
        "sql": """SELECT 
    CASE WHEN SUM(SumMoney) > 0 
        THEN ROUND((SUM(SumMoney) - COALESCE(SUM(SumCostMoney),0)) / SUM(SumMoney) * 100, 2) 
        ELSE 0 END as value
FROM MasterBill 
WHERE BillType=1 AND BillState>=3 AND Period=:period""",
        "desc": "销售毛利率 = (收入-成本)/收入*100",
    },
    "C_CUST_001": {  # 活跃客户数
        "table": "MasterBill",
        "sql": """SELECT COUNT(DISTINCT Unit_ID) as value
FROM MasterBill 
WHERE BillType=1 AND BillState>=3 AND Period=:period""",
        "desc": "活跃客户数 = 有销售业务的客户数",
    },
    "C_CUST_002": {  # 前5客户集中度
        "table": "MasterBill",
        "sql": """SELECT 
    CASE WHEN total_sales > 0 
        THEN ROUND(top5_sales / total_sales * 100, 2) 
        ELSE 0 END as value
FROM (
    SELECT 
        SUM(CASE WHEN rn <= 5 THEN SumMoney ELSE 0 END) as top5_sales,
        SUM(SumMoney) as total_sales
    FROM (
        SELECT SumMoney, 
            ROW_NUMBER() OVER (ORDER BY SumMoney DESC) as rn
        FROM (
            SELECT Unit_ID, SUM(SumMoney) as SumMoney
            FROM MasterBill 
            WHERE BillType=1 AND BillState>=3 AND Period=:period
            GROUP BY Unit_ID
        ) t
    ) t2
) t3""",
        "desc": "前5客户集中度 = 前5客户销售额/总销售额*100",
    },
    "F_AR_002": {  # 逾期应收账款率
        "table": "MasterBill",
        "sql": """SELECT 
    CASE WHEN SUM(CASE WHEN BillType=1 THEN SumMoney ELSE 0 END) > 0
        THEN ROUND(
            SUM(CASE WHEN BillType=1 AND BillState>=3 AND DATEDIFF(day, BillDate, GETDATE()) > 30 THEN SumMoney ELSE 0 END)
            / NULLIF(SUM(CASE WHEN BillType=1 THEN SumMoney ELSE 0 END), 0) * 100, 2)
        ELSE 0 END as value
FROM MasterBill
WHERE BillType=1 AND Period<=:period""",
        "desc": "逾期应收账款率 = 超30天未收金额/总应收",
    },
    "F_COST_002": {  # 预算执行偏差率
        "table": "kpi_values",
        "sql": """SELECT 
    CASE WHEN budget_value > 0 
        THEN ROUND((actual_value - budget_value) / budget_value * 100, 2)
        ELSE 0 END as value
FROM (
    SELECT 
        MAX(CASE WHEN kpi_code='F_REVENUE_001' THEN actual_value ELSE 0 END) as actual_value,
        MAX(CASE WHEN kpi_code='BUDGET_REVENUE' THEN actual_value ELSE 0 END) as budget_value
    FROM kpi_values kv
    JOIN kpi_definitions kd ON kv.kpi_id = kd.id
    WHERE kv.period = :period
) t""",
        "desc": "预算执行偏差率 = (实际-预算)/预算*100",
    },
    "P_INV_001": {  # 存货周转率
        "table": "MasterBill",
        "sql": """SELECT 
    CASE WHEN avg_inventory > 0 
        THEN ROUND(SUM(SumCostMoney) / avg_inventory, 2) 
        ELSE 0 END as value
FROM (
    SELECT SUM(SumCostMoney) as SumCostMoney
    FROM MasterBill 
    WHERE BillType=1 AND BillState>=3 AND Period=:period
) sales
CROSS JOIN (
    SELECT COALESCE(AVG(quantity), 0) as avg_inventory
    FROM (
        SELECT SUM(quantity) as quantity
        FROM Storage
        GROUP BY Prod_ID
    ) inv
) inv_avg""",
        "desc": "存货周转率 = 销售成本/平均库存",
    },
    "F_COST_001": {  # 费用控制率
        "table": "MasterBill",
        "sql": """SELECT 
    CASE WHEN SUM(CASE WHEN BillType=1 THEN SumMoney ELSE 0 END) > 0
        THEN ROUND(
            COALESCE(SUM(CASE WHEN BillType=6 THEN SumMoney ELSE 0 END), 0)
            / NULLIF(SUM(CASE WHEN BillType=1 THEN SumMoney ELSE 0 END), 0) * 100, 2)
        ELSE 0 END as value
FROM MasterBill
WHERE Period=:period AND BillState>=3""",
        "desc": "费用控制率 = 费用支出/销售收入*100（BillType=6为费用单）",
    },
    "F_AR_001": {  # 应收账款周转率
        "table": "MasterBill",
        "sql": """SELECT 
    CASE WHEN avg_receivable > 0
        THEN ROUND(total_sales / avg_receivable, 2)
        ELSE 0 END as value
FROM (
    SELECT COALESCE(SUM(SumMoney), 0) as total_sales
    FROM MasterBill 
    WHERE BillType=1 AND BillState>=3 AND Period=:period
) sales
CROSS JOIN (
    SELECT COALESCE(AVG(receivable), 0) as avg_receivable
    FROM (
        SELECT SUM(AReceive) as receivable
        FROM Units
        WHERE AReceive > 0
    ) ar
) ar_avg""",
        "desc": "应收账款周转率 = 销售收入/平均应收账款",
    },
}


def get_kpis_from_db() -> list:
    """从数据库获取KPI定义"""
    engine = get_engine()
    with engine.connect() as conn:
        rows = conn.execute(text("""
            SELECT id, kpi_code, kpi_name, formula, data_source_type
            FROM kpi_definitions
            ORDER BY id
        """)).fetchall()
    return [dict(r._mapping) for r in rows]


def generate_sql_for_kpi(kpi: dict) -> dict:
    """为单个KPI生成SQL"""
    code = kpi["kpi_code"]
    if code in KPI_SQL_MAP:
        return KPI_SQL_MAP[code]
    
    # 对于没有预定义SQL的KPI，尝试根据formula自动推断
    formula = kpi.get("formula", "") or ""
    
    # manual 类型的KPI标记为需人工确认
    if kpi["data_source_type"] == "manual":
        return {
            "table": "manual",
            "sql": None,
            "desc": f"需人工录入: {formula[:80]}" if formula else "需人工录入",
        }
    
    return {"table": None, "sql": None, "desc": "未找到映射"}


def test_sql(sql: str, period: str = "2026-05") -> dict:
    """通过erp-api-gateway测试SQL执行"""
    if not sql:
        return {"success": False, "error": "无SQL"}
    
    # 替换占位符
    period_month = period.split("-")[1]
    period_year = period.split("-")[0]
    
    # 注意：erp-api-gateway只支持单表查询，不支持复杂SQL
    # 需要通过其底层SQL Server直接执行
    # 这里测试SQL语法正确性
    test_sql = sql.replace(":period", f"'{period}'")
    test_sql = re.sub(r"GETDATE\(\)", f"'{datetime.now().strftime('%Y-%m-%d')}'", test_sql)
    
    return {"success": True, "sql": test_sql, "note": "语法检查通过，需在SQL Server端执行"}


def main():
    kpis = get_kpis_from_db()
    logger.info(f"共 {len(kpis)} 个KPI")
    
    results = []
    for kpi in kpis:
        mapping = generate_sql_for_kpi(kpi)
        
        # 测试SQL
        test_result = test_sql(mapping.get("sql"))
        
        results.append({
            "id": kpi["id"],
            "code": kpi["kpi_code"],
            "name": kpi["kpi_name"],
            "source_type": kpi["data_source_type"],
            "table": mapping.get("table"),
            "sql": mapping.get("sql"),
            "desc": mapping.get("desc"),
            "test": test_result,
        })
    
    # 按数据源类型输出
    erp_ok = [r for r in results if r["source_type"] == "erp" and r["sql"]]
    erp_missing = [r for r in results if r["source_type"] == "erp" and not r["sql"]]
    manual = [r for r in results if r["source_type"] == "manual"]
    
    print("\n" + "="*80)
    print("KPI-SQL 生成结果")
    print("="*80)
    
    print(f"\n✅ ERP可自动获取 ({len(erp_ok)}个):")
    for r in erp_ok:
        sql_short = r["sql"][:80] + "..." if r["sql"] and len(r["sql"]) > 80 else r["sql"]
        print(f"  [{r['code']:20s}] {r['name']:20s} → {r['table']:15s} | {sql_short}")
    
    if erp_missing:
        print(f"\n⚠️ 标记了ERP但无SQL ({len(erp_missing)}个):")
        for r in erp_missing:
            print(f"  [{r['code']:20s}] {r['name']:20s} → 需补充映射")
    
    print(f"\n⚪ 需人工录入 ({len(manual)}个):")
    for r in manual[:5]:
        print(f"  [{r['code']:20s}] {r['name']:20s} → {r['desc'][:60]}")
    if len(manual) > 5:
        print(f"  ... 共{len(manual)}个")
    
    # 保存结果
    with open("/tmp/kpi_sql_mapping.json", "w") as f:
        json.dump(results, f, ensure_ascii=False, indent=2)
    logger.info(f"\n结果已保存: /tmp/kpi_sql_mapping.json")


if __name__ == "__main__":
    main()
