"""补充更多KPI-ERP数据同步
运行: python3 scripts/extend_erp_sync.py
"""
import sys, os, logging
from os import getenv
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app.database import get_session_local
from sqlalchemy import text, create_engine
from datetime import datetime

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

erp_user = os.getenv("ERP_DB_USER", "zxbtest")
erp_pass = os.getenv("ERP_DB_PASS")
erp_host = os.getenv("ERP_DB_HOST", "211.149.143.215")
erp_port = os.getenv("ERP_DB_PORT", "1433")
erp_db = os.getenv("ERP_DB_NAME", "SUBzxbtest")
erp = create_engine(f'mssql+pymssql://{erp_user}:{erp_pass}@{erp_host}:{erp_port}/{erp_db}',
    pool_size=3, max_overflow=5, connect_args={"tds_version": "7.0"})
db = get_session_local()()

kpi_map = {}
rows = db.execute(text("SELECT id, kpi_code FROM kpi_definitions")).fetchall()
for r in rows:
    kpi_map[r[1]] = r[0]

batch = f"erp_sync_{datetime.now().strftime('%Y%m%d_%H%M')}"
written = 0

def p2ym(p):
    base_year, base_period = 2021, 3
    diff = p - base_period
    year = base_year + diff // 12
    month = (diff % 12) + 3
    if month > 12: month -= 12; year += 1
    return f"{year}-{month:02d}"

def write_kpi(code, period, value):
    global written
    kid = kpi_map.get(code)
    if not kid or value is None: return
    try:
        db.execute(text("""
            INSERT INTO kpi_values (kpi_id, period, actual_value, source_type, source_batch, data_status, calculated_at)
            VALUES (:kpi_id, :period, :value, 'erp', :batch, 'verified', NOW())
            ON DUPLICATE KEY UPDATE actual_value=:value2, source_batch=:batch2, data_status='verified', calculated_at=NOW()
        """), {"kpi_id": kid, "period": period, "value": float(value),
               "batch": batch, "value2": float(value), "batch2": batch})
        db.commit()
        written += 1
    except Exception as e:
        db.rollback()

with erp.connect() as c:
    # 获取全期间销售收入
    rev_rows = c.execute(text("""
        SELECT Period, SUM(SumMoney) as rev, COALESCE(SUM(SumCostMoney),0) as cost
        FROM MasterBill WHERE BillType=1 AND BillState>=3
        GROUP BY Period ORDER BY Period
    """)).fetchall()
    
    # 库存总额
    total_inv = float(c.execute(text("SELECT COALESCE(SUM(CostMoney),0) FROM Storage WHERE CostMoney > 0")).fetchone()[0])
    avg_inv = max(total_inv, 1)
    
    # 应收账款总额
    total_ar = float(c.execute(text("SELECT COALESCE(SUM(AReceive),0) FROM Units WHERE AReceive > 0")).fetchone()[0])
    avg_ar = max(total_ar, 1)

for row in rev_rows:
    p = row[0]
    if p < 41: continue
    ps = p2ym(p)
    rev = float(row.rev)
    cost = float(row.cost)
    gross = round((rev - cost) / rev * 100, 2) if rev > 0 else 0
    turnover = round(rev / avg_ar, 2) if avg_ar > 0 else 0
    inv_turn = round(cost / avg_inv, 2) if avg_inv > 0 else 0
    inv_days = round(365 / inv_turn, 1) if inv_turn > 0 else 0
    
    write_kpi("F_REVENUE_001", ps, rev)
    write_kpi("F_PROFIT_001", ps, gross)
    write_kpi("F_AR_001", ps, turnover)
    write_kpi("P_INV_001", ps, inv_turn)
    write_kpi("P_INV_004", ps, inv_days)

# 前5客户集中度 和 逾期应收 另查
with erp.connect() as c:
    for row in rev_rows:
        p = row[0]
        if p < 41: continue
        ps = p2ym(p)
        
        r = c.execute(text("""
            SELECT TOP 5 SUM(SumMoney) as amt FROM (
                SELECT SUM(SumMoney) as SumMoney FROM MasterBill 
                WHERE BillType=1 AND BillState>=3 AND Period=:p GROUP BY Unit_ID
            ) t ORDER BY amt DESC
        """), {"p": p}).fetchall()
        top5 = sum(float(r2[0]) for r2 in r)
        ratio = round(top5 / float(row.rev) * 100, 2) if float(row.rev) > 0 else 0
        write_kpi("C_CUST_002", ps, ratio)
        
        r2 = c.execute(text("""
            SELECT SUM(CASE WHEN DATEDIFF(day, BillDate, GETDATE()) > 30 THEN SumMoney ELSE 0 END) as overdue
            FROM MasterBill WHERE BillType=1 AND BillState>=3 AND Period=:p
        """), {"p": p}).fetchone()
        overdue = float(r2[0]) if r2 and r2[0] else 0
        overdue_ratio = round(overdue / float(row.rev) * 100, 2) if float(row.rev) > 0 else 0
        write_kpi("F_AR_002", ps, overdue_ratio)
    
    # 费用控制率
    r = c.execute(text("""
        SELECT Period,
               SUM(CASE WHEN BillType=1 THEN SumMoney ELSE 0 END) as rev,
               SUM(CASE WHEN BillType=30 THEN SumMoney ELSE 0 END) as expense
        FROM MasterBill WHERE BillState>=3 GROUP BY Period ORDER BY Period
    """)).fetchall()
    for row in r:
        p = row[0]
        if p < 41: continue
        ps = p2ym(p)
        exp_rev = float(row.rev)
        exp_amt = float(row.expense)
        exp_ratio = round(exp_amt / exp_rev * 100, 2) if exp_rev > 0 else 0
        write_kpi("F_COST_001", ps, exp_ratio)

db.close()
logger.info(f"完成! 共写入 {written} 条")
