#!/usr/bin/env python3
"""Auto-Verify 定时验证任务 — 扫描到期pending计划，自动验证执行效果

运行: 30 9 * * * cd /root/cma-management/backend && python3 scripts/auto_verify_cron.py
"""
import sys, os
from datetime import datetime, timedelta

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app.database import get_db
from app.models import ActionPlan, KPIDefinition, KPIValue, Objective
from app.utils.notifier import send_wecom_message
from app.api.verify import CONDITION_FUNCS


def evaluate_condition(condition, actual, target):
    """按条件判断验证结果（兼容旧表达式）"""
    if isinstance(condition, str) and ('<' in condition or '>' in condition):
        try:
            return eval(condition.replace('value', str(actual)), {"__builtins__": {}})
        except Exception:
            return False
    func = CONDITION_FUNCS.get(condition)
    if not func:
        return False
    return func(actual, target)


def run_auto_verify():
    db = next(get_db())
    try:
        now = datetime.now()
        # 扫描到期pending计划（due_date <= now+1天）
        plans = db.query(ActionPlan).filter(
            ActionPlan.verify_status == "pending",
            ActionPlan.status.in_(["pending", "in_progress"]),
            ActionPlan.due_date <= now + timedelta(days=1),
        ).all()

        verified_count = 0
        escalated_count = 0
        messages = []

        for plan in plans:
            rule = plan.auto_verify_rule
            if not rule or not isinstance(rule, dict):
                continue

            kpi_code = rule.get("kpi_code")
            if not kpi_code:
                continue

            # 查最新KPI值
            # 缺陷2残留修复（对齐 verify.py）：从 plan 关联 KPI 向上取 entity_id，kpi_code 查询带 entity_id 过滤（防跨租户误匹配）
            entity_id = None
            if plan.kpi_id:
                pkpi = db.query(KPIDefinition).filter(KPIDefinition.id == plan.kpi_id).first()
                if pkpi:
                    entity_id = pkpi.entity_id
            q = db.query(KPIDefinition).filter(KPIDefinition.kpi_code == kpi_code)
            if entity_id is not None:
                q = q.filter(KPIDefinition.entity_id == entity_id)
            kpi = q.order_by(KPIDefinition.id.desc()).first()
            if not kpi:
                continue
            # 缺陷3残留修复（对齐 verify.py）：KPIValue 按 period <= 当前月过滤，跨月验证不取未来期间
            period_limit = now.strftime("%Y-%m")
            latest = db.query(KPIValue).filter(
                KPIValue.kpi_id == kpi.id,
                KPIValue.actual_value.isnot(None),
                KPIValue.period <= period_limit,
            ).order_by(KPIValue.period.desc(), KPIValue.calculated_at.desc(), KPIValue.id.desc()).first()
            if not latest or latest.actual_value is None:
                continue

            actual = latest.actual_value
            condition = rule.get("condition", "LESS_THAN")
            target = rule.get("target_value")
            retry_max = rule.get("retry_max", 3)

            passed = evaluate_condition(condition, actual, target)

            plan.kpi_current_before = rule.get("baseline_value")
            plan.kpi_current_after = actual

            if passed:
                # 缺陷1残留修复（对齐 verify.py）：plan 已处于"验证通过"状态（passed + verified_at 非空）则跳过 OKR 累加，防重复累加
                already_verified = bool(plan.verify_status == "passed" and plan.verified_at is not None)
                plan.verify_status = "passed"
                plan.verified_at = now
                plan.status = "completed"  # 缺陷4残留修复："done" 不在枚举(pending/in_progress/completed/cancelled)，改 completed
                plan.progress = 100
                # 阶段3: OKR progress更新
                update_okr_progress(db, plan, +15, already_verified=already_verified)
                messages.append(f"✅ 行动计划#{plan.id}验证通过: {plan.title} ({kpi_code}: {rule.get('baseline_value')}→{actual})")
                verified_count += 1
            else:
                plan.verify_attempts = (plan.verify_attempts or 0) + 1
                if plan.verify_attempts >= retry_max:
                    plan.verify_status = "escalated"
                    messages.append(f"🚨 行动计划#{plan.id}连续{retry_max}次验证失败，升级人工: {plan.title}")
                    escalated_count += 1
                else:
                    plan.verify_status = "retrying"
                    messages.append(f"⚠️ 行动计划#{plan.id}验证失败(第{plan.verify_attempts}次)，待重试: {plan.title}")

        db.commit()

        # 汇总通知
        if messages:
            summary = "\n".join(messages)
            try:
                send_wecom_message(f"📋 行动计划自动验证日报\n{summary}", title="Auto-Verify")
            except Exception:
                pass

        print(f"[{now.strftime('%Y-%m-%d %H:%M')}] 验证通过{verified_count}个，升级{escalated_count}个，共处理{len(plans)}个到期计划")
        return {"verified": verified_count, "escalated": escalated_count, "total": len(plans)}
    finally:
        db.close()


def update_okr_progress(db, plan, delta, already_verified=False):
    """验证通过→更新所属OKR progress

    缺陷1残留修复（对齐 verify.py 2026-08-30）：幂等防重复累加
      - already_verified=True（plan 已处于验证通过状态且 verified_at 非空）→ 跳过累加，保持原值
    """
    okr_id = getattr(plan, "okr_id", None) or getattr(plan, "objective_id", None)
    if not okr_id:
        return {"updated": False, "reason": "no_objective"}
    obj = db.query(Objective).filter(Objective.id == okr_id).first()
    if not obj:
        return {"updated": False, "reason": "objective_not_found"}
    if already_verified:
        return {"updated": False, "reason": "already_verified", "objective_id": obj.id, "progress": obj.progress or 0}
    current = obj.progress or 0
    obj.progress = min(current + delta, 100)
    db.add(obj)
    return {"updated": True, "objective_id": obj.id, "progress": obj.progress}


if __name__ == "__main__":
    run_auto_verify()
