from __future__ import annotations

from copy import deepcopy
from typing import Any

from app.services.risk_rule_generation_interpreter import COMPOSITE_RULE_TEMPLATE_KEY


def list_risk_rule_dsl_examples() -> list[dict[str, Any]]:
    return deepcopy(RISK_RULE_DSL_EXAMPLES)


def get_risk_rule_dsl_example(code: str) -> dict[str, Any] | None:
    for example in RISK_RULE_DSL_EXAMPLES:
        if example["code"] == code:
            return deepcopy(example)
    return None


def _manifest(
    *,
    field_keys: list[str],
    conditions: list[dict[str, Any]],
    hit_logic: dict[str, Any],
    message: str,
    summary: str,
    semantic_type: str,
) -> dict[str, Any]:
    params = {
        "template_key": COMPOSITE_RULE_TEMPLATE_KEY,
        "semantic_type": semantic_type,
        "field_keys": field_keys,
        "conditions": conditions,
        "hit_logic": hit_logic,
        "condition_summary": summary,
        "message_template": message,
        "keywords": [],
    }
    return {"template_key": COMPOSITE_RULE_TEMPLATE_KEY, "params": params}


RISK_RULE_DSL_EXAMPLES: list[dict[str, Any]] = [
    {
        "code": "travel_city_mismatch",
        "title": "差旅票据城市不一致",
        "natural_language": (
            "差旅报销时，读取交通票或住宿票据城市、申报目的地、明细发生地点和报销事由。"
            "若票据城市无法与申报目的地或明细地点形成一致关系，且事由未说明绕行、跨城办事"
            "或临时改签，则标记为高风险并要求补充说明。"
        ),
        "manifest": _manifest(
            field_keys=[
                "attachment.route_cities",
                "attachment.hotel_city",
                "claim.location",
                "item.item_location",
                "claim.reason",
            ],
            conditions=[
                {
                    "id": "attachment_city_evidence_present",
                    "operator": "exists_any",
                    "fields": ["attachment.route_cities", "attachment.hotel_city"],
                },
                {
                    "id": "city_outside_business_scope",
                    "operator": "not_in_scope",
                    "left_fields": ["attachment.route_cities", "attachment.hotel_city"],
                    "right_fields": ["claim.location", "item.item_location"],
                },
                {
                    "id": "missing_reasonable_exception",
                    "operator": "not_contains_any",
                    "fields": ["claim.reason"],
                    "keywords": ["绕行", "跨城", "改签", "临时任务"],
                },
            ],
            hit_logic={
                "all": [
                    "attachment_city_evidence_present",
                    "city_outside_business_scope",
                    "missing_reasonable_exception",
                ]
            },
            message="票据城市与申报行程城市不一致，且未说明合理绕行或改签原因。",
            summary="票据城市集合与申报行程城市集合无交集，且缺少合理例外说明时命中。",
            semantic_type="travel_route_city_consistency",
        ),
    },
    {
        "code": "lodging_date_outside_range",
        "title": "住宿日期超出差旅行程",
        "natural_language": (
            "差旅住宿报销时，读取住宿票据日期、差旅开始日期、差旅结束日期和报销事由。"
            "若住宿发生时间早于出差开始或晚于出差结束，且没有延期、改签、临时任务说明，"
            "则标记为高风险。"
        ),
        "manifest": _manifest(
            field_keys=[
                "attachment.stay_start_date",
                "attachment.stay_end_date",
                "claim.trip_start_date",
                "claim.trip_end_date",
                "claim.reason",
            ],
            conditions=[
                {
                    "id": "lodging_date_evidence_present",
                    "operator": "exists_any",
                    "fields": ["attachment.stay_start_date", "attachment.stay_end_date"],
                },
                {
                    "id": "lodging_date_outside_trip_range",
                    "operator": "date_outside_range",
                    "date_fields": ["attachment.stay_start_date", "attachment.stay_end_date"],
                    "range_start_fields": ["claim.trip_start_date"],
                    "range_end_fields": ["claim.trip_end_date"],
                    "tolerance_days": 0,
                },
                {
                    "id": "missing_lodging_exception",
                    "operator": "not_contains_any",
                    "fields": ["claim.reason"],
                    "keywords": ["延期", "改签", "临时任务"],
                },
            ],
            hit_logic={
                "all": [
                    "lodging_date_evidence_present",
                    "lodging_date_outside_trip_range",
                    "missing_lodging_exception",
                ]
            },
            message="住宿日期超出本次差旅行程范围，且未说明延期或临时任务原因。",
            summary="住宿票据日期不在差旅行程日期范围内，且缺少合理例外说明时命中。",
            semantic_type="lodging_date_range_consistency",
        ),
    },
    {
        "code": "budget_threshold",
        "title": "申请金额超过可用预算",
        "natural_language": (
            "费用申请时，读取申请金额和当前可用预算。若申请金额超过可用预算余额，"
            "则提示预算风险并要求补充审批说明。"
        ),
        "manifest": _manifest(
            field_keys=["claim.amount", "budget.remaining_amount", "claim.reason"],
            conditions=[
                {
                    "id": "amount_exceeds_budget",
                    "operator": "numeric_compare",
                    "left_fields": ["claim.amount"],
                    "right_fields": ["budget.remaining_amount"],
                    "compare": "gt",
                }
            ],
            hit_logic={"all": ["amount_exceeds_budget"]},
            message="申请金额超过当前可用预算余额。",
            summary="申请金额大于可用预算余额时命中。",
            semantic_type="budget_available_balance_check",
        ),
    },
    {
        "code": "duplicate_invoice",
        "title": "重复发票识别",
        "natural_language": (
            "费用报销时，读取附件识别出的发票号码和报销明细中的附件编号。若同一发票号"
            "在本次提交中重复出现，则标记为高风险并要求删除重复票据或补充说明。"
        ),
        "manifest": _manifest(
            field_keys=["attachment.invoice_no", "item.invoice_id", "claim.reason"],
            conditions=[
                {
                    "id": "same_invoice_no_repeated",
                    "operator": "duplicate_value",
                    "fields": ["attachment.invoice_no", "item.invoice_id"],
                }
            ],
            hit_logic={"all": ["same_invoice_no_repeated"]},
            message="同一发票号在本次提交中重复出现。",
            summary="附件发票号或明细附件编号出现重复值时命中。",
            semantic_type="duplicate_invoice_check",
        ),
    },
    {
        "code": "entertainment_per_capita_over_limit",
        "title": "招待人均金额超标",
        "natural_language": (
            "业务招待报销时，读取申报总金额、参与人数、人均金额和报销事由。若人均金额"
            "超过公司招待标准 500 元，且没有高级审批或特殊客户接待说明，则标记为中风险。"
        ),
        "manifest": _manifest(
            field_keys=[
                "claim.amount",
                "claim.attendee_count",
                "claim.per_capita_amount",
                "claim.reason",
            ],
            conditions=[
                {
                    "id": "per_capita_amount_exceeds_limit",
                    "operator": "numeric_compare",
                    "left_fields": ["claim.per_capita_amount"],
                    "threshold": 500,
                    "compare": "gt",
                },
                {
                    "id": "missing_special_approval_reason",
                    "operator": "not_contains_any",
                    "fields": ["claim.reason"],
                    "keywords": ["高级审批", "特殊客户", "重要客户", "专项审批"],
                },
            ],
            hit_logic={"all": ["per_capita_amount_exceeds_limit", "missing_special_approval_reason"]},
            message="业务招待人均金额超过公司标准，且缺少特殊审批或客户接待说明。",
            summary="人均金额大于招待标准阈值，且缺少合理审批说明时命中。",
            semantic_type="entertainment_per_capita_limit_check",
        ),
    },
]
