"""
本土红旗五因子计算器(R1-R5)。

作为 Beneish M-Score 的本土业务场景补充,本模块提供以下可复算规则:

  R1(净现比异常):
    net_profit_cur > 0 且 cfo_cur < 0 → 严重红旗
    net_profit_cur > 0 且 cfo_cur > 0 且 cfo_cur/net_profit_cur < 0.5 → 普通红旗

  R2(存货+资金异常增幅):
    任一分支满足即触发:
      (A) monetary_funds YoY > 1.70 AND inventory YoY > 1.45
      (B) (monetary_funds_cur + inventory_cur) / current_assets_cur > 0.82

  R3(存贷双高):
    monetary_funds_cur/total_assets_cur > 0.20
    AND (short_term_borrowings_cur+long_term_borrowings_cur)/total_assets_cur > 0.15

  R4(关联方/应收款占比异常):
    accounts_receivable_cur / total_assets_cur > 0.18(通用阈值,可由行业参数覆盖)

  R5(存货异常加强版):
    inventory YoY > 0.30 AND revenue YoY < 0.10

所有 None 情况均返回 triggered=False,不抛异常。
"""
from typing import Dict, Optional, Tuple
import logging

from config.settings import settings

logger = logging.getLogger(__name__)


class RedFlagCalculator:
    """本土红旗五因子(R1-R5)计算器。"""

    # ════════════════════════════════════════════════════════════
    # 通用阈值(基于 141 家公司跨行业校准,目标 2-15% 触发率)
    # ════════════════════════════════════════════════════════════

    # ====== R1 阈值 ======
    R1_CFO_NEGATIVE = 0.0          # 经营现金流为负(净利润>0时)即严重红旗
    R1_NETPROFIT_TO_CFO_RATIO = 0.5  # cfo/net_profit < 0.5 → 普通红旗

    # ====== R2 阈值 ======
    # 注意:YoY 阈值 = 本期/上期比值(不是增长率百分比)。
    # 例如 1.7 代表「本期/上期 > 1.7 → 同比增长 > 70%」。
    R2_YOY_THRESHOLD_FUNDS = 1.7      # 货币资金 YoY 比值 > 1.7(即同比增长 > 70%)
    R2_YOY_THRESHOLD_INVENTORY = 1.45 # 存货 YoY 比值 > 1.45(即同比增长 > 45%)
    R2_FUNDS_INVENTORY_RATIO = 0.82   # (货币资金+存货)/流动资产 > 82%

    # ====== R3 阈值 ======
    R3_FUNDS_TO_ASSETS = 0.20      # 货币资金/总资产 > 20%
    R3_BORROWINGS_TO_ASSETS = 0.15  # (短借+长借)/总资产 > 15%

    # ====== R4 阈值 ======
    R4_AR_TO_ASSETS = 0.18         # 从 0.15 上调至 0.18(从 10.6%→~6% 触发率)

    # ====== R5 阈值 ======
    R5_INVENTORY_GROWTH = 0.30     # 存货同比增长 > 30%
    R5_REVENUE_GROWTH = 0.10       # 营收同比增长 < 10%(存货堆积但卖不动)

    # ════════════════════════════════════════════════════════════
    # 行业专用阈值(仅覆盖通用阈值会产生系统性偏差的行业)
    # 原则:各行业内目标 ~5-15% 触发率
    # ════════════════════════════════════════════════════════════
    INDUSTRY_ADJUSTMENTS: Dict[str, Dict[str, float]] = {
        # ── R2_B + R3 组合(资金存货占比与账上资金天然双高的行业)──
        # 白酒/零售/食品饮料/半导体 既需上调 R2_B,又需上调 R3 资金占比阈值
        "白酒":     {"R2_B": 0.92, "R3_funds_to_assets": 0.40},
        "零售":     {"R2_B": 0.90, "R3_funds_to_assets": 0.40},
        "食品饮料": {"R2_B": 0.88, "R3_funds_to_assets": 0.32},
        "半导体":   {"R2_B": 0.84, "R3_funds_to_assets": 0.28},

        # ── 仅 R2_B(资金或存货占比天然高)──
        "农牧":     {"R2_B": 0.84},
        "化工":     {"R2_B": 0.84},
        "房地产":   {"R2_B": 0.84},

        # ── 仅 R3(账上资金占比天然高)──
        "汽车":     {"R3_funds_to_assets": 0.28},

        # ── R4(应收款结构天然偏高)──
        "通信":     {"R4": 0.24},
        "科技":     {"R4": 0.22},
        "军工":     {"R4": 0.22},
        "医药":     {"R4": 0.22},
    }

    @staticmethod
    def _safe_get(data: Dict, key: str, idx: int) -> Optional[float]:
        """安全获取 (current, previous) 元组/列表的某一位。

        兼容 tuple 和 list(JSON 反序列化产生 list,代码内用 tuple),
        与 f_score.py._safe_get 行为对齐。
        """
        v = data.get(key, (None, None))
        if not isinstance(v, (tuple, list)) or len(v) <= idx:
            return None
        return v[idx]

    @staticmethod
    def _yoy(current: Optional[float], previous: Optional[float]) -> Optional[float]:
        """计算同比 ratio = current/previous,None 或零分母返回 None"""
        if current is None or previous is None:
            return None
        if previous == 0:
            return None
        return current / previous

    @classmethod
    def _get_industry_threshold(
        cls, industry: Optional[str], threshold_key: str, default: float
    ) -> float:
        """
        获取行业修正后的阈值。
        如果行业在 INDUSTRY_ADJUSTMENTS 中且该 key 存在,返回行业专用值;
        否则返回通用默认值。
        """
        if industry and industry in cls.INDUSTRY_ADJUSTMENTS:
            adjusted = cls.INDUSTRY_ADJUSTMENTS[industry].get(threshold_key)
            if adjusted is not None:
                return adjusted
        return default

    # ============================================================
    # R1:净现比异常
    # ============================================================
    def calculate_r1(self, financial_data: Dict[str, Tuple[float, float]]) -> Dict:
        """
        R1(净现比异常):
          net_profit_cur > 0 且 cfo_cur < 0 → 严重红旗
          net_profit_cur > 0 且 cfo_cur > 0 且 cfo_cur/net_profit_cur < 0.5 → 普通红旗
        """
        net_profit_cur = self._safe_get(financial_data, 'net_profit', 0)
        cfo_cur = self._safe_get(financial_data, 'cash_flow_operations', 0)

        triggered = False
        severity = "未触发"  # 严重红旗 / 普通红旗 / 未触发
        reason = ""
        detail = {
            'net_profit_cur': net_profit_cur,
            'cfo_cur': cfo_cur,
            'cfo_to_net_profit_ratio': None,  # 预初始化,保证 detail 结构固定
        }

        # 数据缺失 → 不触发
        if net_profit_cur is None or cfo_cur is None:
            return self._build_r1_result(False, "未触发", "数据缺失", detail)

        # 严重红旗:净利润>0 但经营现金流<0
        if net_profit_cur > 0 and cfo_cur < 0:
            triggered = True
            severity = "严重红旗"
            reason = (f"净利润为正({net_profit_cur:.2f})但经营现金流为负"
                      f"({cfo_cur:.2f}),盈余质量严重可疑")

        # 普通红旗:净利润>0、现金流>0,但 cfo/净利润 < 0.5
        elif net_profit_cur > 0 and cfo_cur > 0:
            if net_profit_cur == 0:
                ratio = None
            else:
                ratio = cfo_cur / net_profit_cur
            detail['cfo_to_net_profit_ratio'] = ratio
            if ratio is not None and ratio < self.R1_NETPROFIT_TO_CFO_RATIO:
                triggered = True
                severity = "普通红旗"
                reason = (f"经营现金流/净利润={ratio:.3f} < {self.R1_NETPROFIT_TO_CFO_RATIO},"
                          f"净利润缺少现金流支撑")

        return self._build_r1_result(triggered, severity, reason, detail)

    @staticmethod
    def _build_r1_result(triggered: bool, severity: str, reason: str, detail: Dict) -> Dict:
        return {
            'flag_id': 'R1',
            'name': '净现比异常',
            'description': '净利润与经营活动现金流的匹配度',
            'triggered': triggered,
            'severity': severity,
            'reason': reason,
            'detail': detail,
        }

    # ============================================================
    # R2:存货+资金异常增幅
    # ============================================================
    def calculate_r2(self, financial_data: Dict[str, Tuple[float, float]],
                      industry: Optional[str] = None) -> Dict:
        """
        R2(存货+资金异常增幅):
          (A) monetary_funds YoY > 1.7 AND inventory YoY > 1.45
          (B) (monetary_funds_cur + inventory_cur) / current_assets_cur > 阈值(含行业修正)
        任一分支满足即触发。
        """
        funds_cur = self._safe_get(financial_data, 'monetary_funds', 0)
        funds_prev = self._safe_get(financial_data, 'monetary_funds', 1)
        inv_cur = self._safe_get(financial_data, 'inventory', 0)
        inv_prev = self._safe_get(financial_data, 'inventory', 1)
        ca_cur = self._safe_get(financial_data, 'current_assets', 0)

        funds_yoy = self._yoy(funds_cur, funds_prev)
        inv_yoy = self._yoy(inv_cur, inv_prev)

        # 分支 A:货币资金 + 存货 同比 YoY(拆分阈值:资金 1.7 / 存货 1.45)
        branch_a_triggered = (
            funds_yoy is not None
            and inv_yoy is not None
            and funds_yoy > self.R2_YOY_THRESHOLD_FUNDS
            and inv_yoy > self.R2_YOY_THRESHOLD_INVENTORY
        )

        # 分支 B:(资金 + 存货) / 流动资产(含行业修正)
        r2b_threshold = self._get_industry_threshold(industry, "R2_B", self.R2_FUNDS_INVENTORY_RATIO)
        branch_b_triggered = False
        funds_inv_ratio = None
        if (funds_cur is not None and funds_cur != 0
                and inv_cur is not None and inv_cur != 0
                and ca_cur is not None and ca_cur != 0):
            funds_inv_ratio = (funds_cur + inv_cur) / ca_cur
            if funds_inv_ratio > r2b_threshold:
                branch_b_triggered = True

        triggered = branch_a_triggered or branch_b_triggered

        # 构建原因
        reasons = []
        if branch_a_triggered:
            reasons.append(
                f"分支A:货币资金YoY={funds_yoy:.2f}>{self.R2_YOY_THRESHOLD_FUNDS} "
                f"且 存货YoY={inv_yoy:.2f}>{self.R2_YOY_THRESHOLD_INVENTORY}"
            )
        if branch_b_triggered:
            threshold_type = "行业" if r2b_threshold != self.R2_FUNDS_INVENTORY_RATIO else "通用"
            reasons.append(
                f"分支B:(资金+存货)/流动资产={funds_inv_ratio:.3f}>{r2b_threshold}{threshold_type}阈值)"
            )
        if not triggered:
            reasons.append("未达到任一分支阈值")

        severity = "普通红旗" if triggered else "未触发"

        detail = {
            'funds_cur': funds_cur,
            'funds_prev': funds_prev,
            'funds_yoy': funds_yoy,
            'inventory_cur': inv_cur,
            'inventory_prev': inv_prev,
            'inventory_yoy': inv_yoy,
            'current_assets_cur': ca_cur,
            'funds_inventory_to_current_assets': funds_inv_ratio,
            'branch_a_triggered': branch_a_triggered,
            'branch_b_triggered': branch_b_triggered,
        }

        return {
            'flag_id': 'R2',
            'name': '存货+资金异常增幅',
            'description': '货币资金/存货同比异常增长 或 占流动资产比例过高',
            'triggered': triggered,
            'severity': severity,
            'reason': ";".join(reasons),
            'detail': detail,
        }

    # ============================================================
    # R3:存贷双高
    # ============================================================
    def calculate_r3(self, financial_data: Dict[str, Tuple[float, float]],
                      industry: Optional[str] = None) -> Dict:
        """
        R3(存贷双高):
          monetary_funds_cur/total_assets_cur > 阈值(含行业修正)
          AND (short_term_borrowings_cur+long_term_borrowings_cur)/total_assets_cur > 0.15
          同时满足 → 触发
        """
        funds_cur = self._safe_get(financial_data, 'monetary_funds', 0)
        ta_cur = self._safe_get(financial_data, 'total_assets', 0)
        stb_cur = self._safe_get(financial_data, 'short_term_borrowings', 0)
        ltb_cur = self._safe_get(financial_data, 'long_term_borrowings', 0)

        # 资金/总资产(含行业修正)
        r3_funds_threshold = self._get_industry_threshold(industry, "R3_funds_to_assets", self.R3_FUNDS_TO_ASSETS)

        funds_to_assets = None
        if funds_cur is not None and ta_cur is not None and ta_cur != 0:
            funds_to_assets = funds_cur / ta_cur

        # (短借+长借)/总资产
        borrowings_to_assets = None
        if (stb_cur is not None or ltb_cur is not None) and ta_cur is not None and ta_cur != 0:
            stb = stb_cur if stb_cur is not None else 0.0
            ltb = ltb_cur if ltb_cur is not None else 0.0
            borrowings_to_assets = (stb + ltb) / ta_cur

        # 两个条件同时满足
        cond_a = (funds_to_assets is not None
                  and funds_to_assets > r3_funds_threshold)
        cond_b = (borrowings_to_assets is not None
                  and borrowings_to_assets > self.R3_BORROWINGS_TO_ASSETS)
        triggered = cond_a and cond_b

        severity = "严重红旗" if triggered else "未触发"

        threshold_type = "行业" if r3_funds_threshold != self.R3_FUNDS_TO_ASSETS else "通用"
        reasons = []
        if cond_a:
            reasons.append(
                f"资金/总资产={funds_to_assets:.3f}>{r3_funds_threshold}{threshold_type}阈值)"
            )
        else:
            reasons.append(
                f"资金/总资产={'N/A' if funds_to_assets is None else f'{funds_to_assets:.3f}'}"
                f"未超{r3_funds_threshold}"
            )
        if cond_b:
            reasons.append(
                f"借款/总资产={borrowings_to_assets:.3f}>{self.R3_BORROWINGS_TO_ASSETS}"
            )
        else:
            reasons.append(
                f"借款/总资产={'N/A' if borrowings_to_assets is None else f'{borrowings_to_assets:.3f}'}"
                f"未超{self.R3_BORROWINGS_TO_ASSETS}"
            )
        if not triggered:
            reasons.append("两条件未同时满足")

        detail = {
            'funds_cur': funds_cur,
            'total_assets_cur': ta_cur,
            'short_term_borrowings_cur': stb_cur,
            'long_term_borrowings_cur': ltb_cur,
            'funds_to_assets': funds_to_assets,
            'funds_to_assets_threshold': r3_funds_threshold,
            'borrowings_to_assets': borrowings_to_assets,
            'cond_a_satisfied': cond_a,
            'cond_b_satisfied': cond_b,
        }

        return {
            'flag_id': 'R3',
            'name': '存贷双高',
            'description': f'货币资金占总资产>{r3_funds_threshold*100:.0f}% 且 短借+长借占总资产>{self.R3_BORROWINGS_TO_ASSETS*100:.0f}%',
            'triggered': triggered,
            'severity': severity,
            'reason': ";".join(reasons),
            'detail': detail,
        }

    # ============================================================
    # R4:关联方/应收款占比异常
    # ============================================================
    def calculate_r4(self, financial_data: Dict[str, Tuple[float, float]],
                      industry: Optional[str] = None) -> Dict:
        """
        R4(关联方/应收款占比异常):
          accounts_receivable_cur / total_assets_cur > 阈值(含行业修正)→ 严重红旗
          (应收款占总资产比例过高,可能存在虚增收入或关联方占款)
        """
        ar_cur = self._safe_get(financial_data, 'accounts_receivable', 0)
        ta_cur = self._safe_get(financial_data, 'total_assets', 0)

        r4_threshold = self._get_industry_threshold(industry, "R4", self.R4_AR_TO_ASSETS)

        ar_to_assets = None
        if ar_cur is not None and ta_cur is not None and ta_cur != 0:
            ar_to_assets = ar_cur / ta_cur

        triggered = (ar_to_assets is not None
                     and ar_to_assets > r4_threshold)

        severity = "严重红旗" if triggered else "未触发"

        threshold_type = "行业" if r4_threshold != self.R4_AR_TO_ASSETS else "通用"
        if triggered:
            reason = (f"应收账款/总资产={ar_to_assets:.3f} > {r4_threshold}{threshold_type}阈值)"
                      f",应收款占比过高,可能存在虚增收入或关联方占款")
        elif ar_to_assets is not None:
            reason = (f"应收账款/总资产={ar_to_assets:.3f} 未超 {r4_threshold}")
        else:
            reason = "数据缺失"

        detail = {
            'accounts_receivable_cur': ar_cur,
            'total_assets_cur': ta_cur,
            'ar_to_assets': ar_to_assets,
            'threshold': r4_threshold,
            'threshold_type': threshold_type,
        }

        return {
            'flag_id': 'R4',
            'name': '关联方/应收款占比异常',
            'description': f'应收账款/总资产 > {r4_threshold*100:.0f}%(虚增收入或关联方占款风险)',
            'triggered': triggered,
            'severity': severity,
            'reason': reason,
            'detail': detail,
        }

    # ============================================================
    # R5:存货异常加强版(存货大增但营收停滞)
    # ============================================================
    def calculate_r5(self, financial_data: Dict[str, Tuple[float, float]]) -> Dict:
        """
        R5(存货异常加强版):
          inventory 同比增长 > 30% AND revenue 同比增长 < 10% → 普通红旗
          (存货大增但营收停滞,存货真实性存疑)
          与 R2 区分:R2 关注"资金+存货双增",R5 关注"存货增但营收不增"
        """
        inv_cur = self._safe_get(financial_data, 'inventory', 0)
        inv_prev = self._safe_get(financial_data, 'inventory', 1)
        rev_cur = self._safe_get(financial_data, 'revenue', 0)
        rev_prev = self._safe_get(financial_data, 'revenue', 1)

        inv_yoy = self._yoy(inv_cur, inv_prev)
        rev_yoy = self._yoy(rev_cur, rev_prev)

        # 同比增长率(百分比变化),None 或分母为零返回 None
        inv_growth = None
        if inv_yoy is not None:
            inv_growth = inv_yoy - 1.0  # current/previous - 1

        rev_growth = None
        if rev_yoy is not None:
            rev_growth = rev_yoy - 1.0

        triggered = (
            inv_growth is not None and inv_growth > self.R5_INVENTORY_GROWTH
            and rev_growth is not None and rev_growth < self.R5_REVENUE_GROWTH
        )

        severity = "普通红旗" if triggered else "未触发"

        reasons = []
        if inv_growth is not None:
            if inv_growth > self.R5_INVENTORY_GROWTH:
                reasons.append(f"存货同比+{inv_growth*100:.1f}% > {self.R5_INVENTORY_GROWTH*100:.0f}%")
            else:
                reasons.append(f"存货同比+{inv_growth*100:.1f}% 未超 {self.R5_INVENTORY_GROWTH*100:.0f}%")
        else:
            reasons.append("存货同比数据缺失")
        if rev_growth is not None:
            if rev_growth < self.R5_REVENUE_GROWTH:
                reasons.append(f"营收同比+{rev_growth*100:.1f}% < {self.R5_REVENUE_GROWTH*100:.0f}%")
            else:
                reasons.append(f"营收同比+{rev_growth*100:.1f}% 未低于 {self.R5_REVENUE_GROWTH*100:.0f}%")
        else:
            reasons.append("营收同比数据缺失")
        if not triggered:
            reasons.append("两条件未同时满足")

        detail = {
            'inventory_cur': inv_cur,
            'inventory_prev': inv_prev,
            'inventory_growth': inv_growth,
            'revenue_cur': rev_cur,
            'revenue_prev': rev_prev,
            'revenue_growth': rev_growth,
        }

        return {
            'flag_id': 'R5',
            'name': '存货异常加强版',
            'description': '存货同比增长>30%且营收增长<10%(存货真实性存疑)',
            'triggered': triggered,
            'severity': severity,
            'reason': ";".join(reasons),
            'detail': detail,
        }

    # ============================================================
    # 综合评估
    # ============================================================
    def evaluate_all(self, financial_data: Dict[str, Tuple[float, float]],
                      industry: Optional[str] = None) -> Dict:
        """
        综合计算 R1/R2/R3/R4/R5 并返回汇总结果。

        输出口径:
          total_red_flags / triggered_count = 实际触发项数
          severity_score = 严重红旗 2 分 + 普通红旗 1 分

        升级规则(risk_upgrade):
          triggered_count ≥ 3 → "高风险(M-Score盲区警告)"
          triggered_count = 2 → "中高风险(M-Score盲区警告)"
          triggered_count = 1 → "关注"
          0        → None

        Args:
            financial_data: 财务数据字典
            industry: 行业分类(可选),用于行业专用阈值修正
        """
        r1 = self.calculate_r1(financial_data)
        r2 = self.calculate_r2(financial_data, industry=industry)
        r3 = self.calculate_r3(financial_data, industry=industry)
        r4 = self.calculate_r4(financial_data, industry=industry)
        r5 = self.calculate_r5(financial_data)

        flags = [r1, r2, r3, r4, r5]

        # 同时保留“实际触发项数”和“严重度积分”,禁止再用一个字段表达两种语义。
        # total_red_flags / triggered_count:实际触发 R1-R5 的数量,用于 RULE-A(≥5项)。
        # severity_score:普通红旗=1分、严重红旗=2分,用于风险强度量化。
        severity_score = 0
        for f in flags:
            if not f['triggered']:
                continue
            sev = f['severity']
            if sev == "严重红旗":
                severity_score += 2
            elif sev == "普通红旗":
                severity_score += 1

        triggered_flags = [f for f in flags if f['triggered']]
        triggered_count = len(triggered_flags)

        # 升级规则
        if triggered_count >= 3:
            risk_upgrade = "高风险(M-Score盲区警告)"
        elif triggered_count == 2:
            risk_upgrade = "中高风险(M-Score盲区警告)"
        elif triggered_count == 1:
            risk_upgrade = "关注"
        else:
            risk_upgrade = None

        result = {
            'R1': r1,
            'R2': r2,
            'R3': r3,
            'R4': r4,
            'R5': r5,
            'total_red_flags': triggered_count,
            'triggered_count': triggered_count,
            'severity_score': severity_score,
            'risk_upgrade': risk_upgrade,
            'triggered_flag_ids': [f['flag_id'] for f in triggered_flags],
            'triggered_flag_names': [f['name'] for f in triggered_flags],
        }
        # 追加 LLM 深度解读(仅对触发的红旗调用,不抛异常)
        result = self.attach_llm_interpretations(result)
        return result

    # ============================================================
    # LLM 深度解读(昇腾 AI · R-ASCEND-1)
    # ============================================================
    @staticmethod
    def _build_interpretation_system_prompt() -> str:
        """构建红旗解读系统 prompt"""
        return (
            "你是一名资深审计专家。请用50-80字中文解读以下财务红旗。"
            "要求:1. 说明该红旗的财务含义与数据可疑点;"
            "2. 对应常见舞弊手法(必须使用虚构公司名案例,如"
            "'某制药公司2017''某白酒企业2025''某新材料公司2017'"
            "'某水产公司2017''某中药公司2019',不允许出现任何真实A股上市公司名称);"
            "3. 给出针对该红旗的1条具体审计建议。"
            "不要输出免责套话,严格控制在80字以内。"
        )

    @staticmethod
    def _build_interpretation_user_prompt(flag_id: str, detail: dict) -> str:
        """构建红旗解读用户 prompt"""
        flag_desc = {
            'R1': '净现比异常红旗(盈利企业经营现金流/净利润 < 0.5 或现金流为负)',
            'R2': '存货+资金异常增幅红旗(货币资金和存货同比大幅增长 或 两者合计占流动资产比例过高)',
            'R3': '存贷双高红旗(账上大量货币资金同时持有大量有息负债)',
            'R4': '关联方/应收款占比异常红旗(通用阈值18%,部分行业按行业阈值覆盖;以触发数据中的threshold为准,可能存在虚增收入或关联方占款)',
            'R5': '存货异常加强版红旗(存货同比增长>30%但营收增长<10%,存货真实性存疑)',
        }
        return (
            f"红旗类型:{flag_desc.get(flag_id, flag_id)}\n"
            f"触发数据:{detail}\n\n"
            f"请按系统指令生成50-80字中文深度解读。"
        )

    def get_llm_interpretation(self, flag_id: str, flag_detail: dict) -> str:
        """
        调用昇腾 API 生成红旗因子的 AI 深度解读。
        永不抛异常——所有失败场景返回兜底字符串。
        """
        if not settings.LLM_ASCEND.get('enabled', True):
            return "AI 解读未启用(离线演示模式)"

        try:
            from core.ascend_adapter import AscendLLMClient
            client = AscendLLMClient()
            system_prompt = self._build_interpretation_system_prompt()
            user_prompt = self._build_interpretation_user_prompt(flag_id, flag_detail)
            return client.chat_completion(
                user_prompt=user_prompt,
                system_prompt=system_prompt,
            )
        except RuntimeError as e:
            msg = str(e)
            if "超时" in msg or "不可用" in msg or "失败" in msg or "未配置" in msg or "空" in msg:
                logger.warning(f"Ascend LLM 调用失败({flag_id}): {msg}")
                return f"AI 解读生成失败(API不可用或超时)"
            logger.warning(f"Ascend LLM 配置异常({flag_id}): {msg}")
            return f"AI 解读生成失败(配置异常)"
        except Exception as e:
            logger.warning(f"Ascend LLM 未知错误({flag_id}): {str(e)[:200]}")
            return f"AI 解读生成失败(未知错误)"

    def attach_llm_interpretations(self, red_flags_result: dict) -> dict:
        """
        为已触发的红旗追加 llm_interpretation 字段。
        未触发的红旗塞空字符串。
        不修改原数据其他字段。
        """
        for flag_id in ['R1', 'R2', 'R3', 'R4', 'R5']:
            flag = red_flags_result.get(flag_id, {})
            if flag.get('triggered', False):
                flag['llm_interpretation'] = self.get_llm_interpretation(
                    flag_id, flag.get('detail', {})
                )
            else:
                flag['llm_interpretation'] = ''
        return red_flags_result


if __name__ == "__main__":
    calc = RedFlagCalculator()

    # 某制药公司2017测试数据
    test_case_2017 = {
        'revenue': (26476970977.57, 21642324070.28),
        'net_profit': (4100926077.16, 3340000000.00),
        'cash_flow_operations': (1842794237.84, 1603189351.32),
        'monetary_funds': (34151000000.00, 27325000000.00),
        'inventory': (15700000000.00, 12619000000.00),
        'short_term_borrowings': (11370000000.00, 8252000000.00),
        'long_term_borrowings': (None, None),
        'total_assets': (68722020630.61, 54823896576.81),
        'current_assets': (56479077718.23, 44461544324.71),
    }
    result = calc.evaluate_all(test_case_2017)
    import json
    print(json.dumps(result, ensure_ascii=False, indent=2, default=str))