from __future__ import annotations

import re
from decimal import Decimal

from app.services.expense_type_keywords import iter_expense_keywords

EXPENSE_TYPE_LABELS = {
    "travel": "差旅",
    "train_ticket": "火车票",
    "flight_ticket": "机票",
    "hotel_ticket": "住宿票",
    "ride_ticket": "乘车",
    "travel_allowance": "出差补贴",
    "hotel": "住宿",
    "transport": "交通",
    "meal": "业务招待",
    "meeting": "会务",
    "entertainment": "招待",
    "marketing": "市场推广",
    "office": "办公用品",
    "training": "培训",
    "software": "软件服务",
    "communication": "通讯",
    "welfare": "福利",
}
MAX_DRAFT_CLAIMS_PER_USER = 3
EDITABLE_CLAIM_STATUSES = ("draft", "supplement", "returned")
STANDARD_ADJUSTMENT_RISK_SOURCE = "reimbursement_standard_adjustment"
SYSTEM_GENERATED_ITEM_TYPES = {"travel_allowance"}
OPTIONAL_ATTACHMENT_ITEM_TYPES = {"ride_ticket", "travel_allowance"}
TRAVEL_DETAIL_ITEM_TYPES = {
    "train_ticket",
    "flight_ticket",
    "hotel_ticket",
    "ride_ticket",
    "travel_allowance",
}
TRAVEL_ALLOWANCE_TRIGGER_ITEM_TYPES = {"train_ticket", "flight_ticket"}
DOCUMENT_TYPE_ITEM_TYPE_MAP = {
    "train_ticket": "train_ticket",
    "flight_itinerary": "flight_ticket",
    "hotel_invoice": "hotel_ticket",
    "taxi_receipt": "ride_ticket",
    "transport_receipt": "ride_ticket",
}
DOCUMENT_TYPE_SCENE_MAP = {
    "train_ticket": "travel",
    "flight_itinerary": "travel",
    "hotel_invoice": "hotel",
    "taxi_receipt": "transport",
    "transport_receipt": "transport",
    "parking_toll_receipt": "transport",
    "meal_receipt": "meal",
    "office_invoice": "office",
    "meeting_invoice": "meeting",
    "training_invoice": "training",
}
DOCUMENT_FACT_ITEM_TYPES = {
    "train_ticket",
    "flight_ticket",
    "hotel_ticket",
    "ride_ticket",
    "ship_ticket",
    "ferry_ticket",
}
ROUTE_DESCRIPTION_ITEM_TYPES = {
    "train_ticket",
    "flight_ticket",
    "ship_ticket",
    "ferry_ticket",
    "ride_ticket",
}
DOCUMENT_TRIP_DATE_LABELS = {
    "train_ticket": "列车出发时间",
    "flight_itinerary": "起飞日期",
    "taxi_receipt": "乘车时间",
    "transport_receipt": "乘车时间",
    "parking_toll_receipt": "通行日期",
}
DOCUMENT_TRIP_DATE_REQUIREMENT_LABELS = {
    "train_ticket": "列车出发时间或乘车日期",
    "flight_itinerary": "起飞日期或航班日期",
    "taxi_receipt": "乘车时间",
    "transport_receipt": "乘车时间",
    "parking_toll_receipt": "通行日期",
    "hotel_invoice": "入住或离店日期",
}
DOCUMENT_TRIP_DATE_KEYS = {
    "traveldate",
    "tripdate",
    "journeydate",
    "departuredate",
    "departuretime",
    "departdate",
    "departtime",
    "boardingdate",
    "boardingtime",
    "traindate",
    "traintime",
    "traindeparturetime",
    "scheduleddeparturetime",
    "flightdate",
    "flighttime",
    "ridedate",
    "ridetime",
    "pickuptime",
    "starttime",
}
DOCUMENT_GENERIC_DATE_KEYS = {"date", "time", "occurredat", "occurreddate", "businessdate"}
DOCUMENT_INVOICE_DATE_KEYS = {"issuedat", "issuedate", "invoicedate", "billingdate"}
DOCUMENT_TRIP_DATE_LABEL_TOKENS = (
    "出发日期",
    "出发时间",
    "列车出发时间",
    "发车日期",
    "发车时间",
    "开车时间",
    "乘车日期",
    "乘车时间",
    "起飞日期",
    "航班日期",
    "行程日期",
    "上车时间",
    "用车时间",
    "通行日期",
)
DOCUMENT_GENERIC_DATE_LABEL_TOKENS = ("日期", "时间", "发生时间", "业务发生日期")
DOCUMENT_INVOICE_DATE_LABEL_TOKENS = ("开票日期", "发票日期")
DOCUMENT_ROUTE_FORMAT_PATTERN = re.compile(
    r"^[A-Za-z0-9\u4e00-\u9fa5（）()·]{2,40}\s*-\s*"
    r"[A-Za-z0-9\u4e00-\u9fa5（）()·]{2,40}$"
)
DOCUMENT_ROUTE_TEXT_PATTERN = re.compile(
    r"([A-Za-z0-9\u4e00-\u9fa5（）()·]{2,40})\s*(?:至|到|→|->|—|–|-)\s*"
    r"([A-Za-z0-9\u4e00-\u9fa5（）()·]{2,40})"
)
DOCUMENT_ROUTE_ORIGIN_LABELS = {
    "起点",
    "上车",
    "上车地点",
    "上车地址",
    "出发",
    "出发地",
    "出发站",
    "始发站",
    "乘车起点",
}
DOCUMENT_ROUTE_DESTINATION_LABELS = {
    "终点",
    "下车",
    "下车地点",
    "下车地址",
    "到达",
    "到达地",
    "到达站",
    "目的地",
    "乘车终点",
}
GENERIC_ATTACHMENT_BACKFILL_ITEM_TYPES = {"", "other", "travel", "transport", "hotel"}
LOCATION_REQUIRED_EXPENSE_TYPES = {"travel", "meeting", "entertainment"}
EXPENSE_SCENE_KEYWORDS = {
    code: tuple(iter_expense_keywords(code))
    for code in (
        "travel",
        "hotel",
        "transport",
        "meal",
        "entertainment",
        "marketing",
        "office",
        "meeting",
        "training",
        "software",
        "communication",
        "welfare",
    )
}
EXPENSE_TYPE_ALLOWED_DOCUMENT_SCENES = {
    "travel": {"travel", "hotel", "transport", "meal"},
    "train_ticket": {"travel"},
    "flight_ticket": {"travel"},
    "hotel_ticket": {"hotel"},
    "ride_ticket": {"transport"},
    "travel_allowance": set(),
    "hotel": {"hotel"},
    "transport": {"transport", "travel"},
    "meal": {"meal", "entertainment"},
    "entertainment": {"entertainment", "meal"},
    "marketing": {"marketing"},
    "office": {"office"},
    "meeting": {"meeting"},
    "training": {"training"},
    "software": {"software"},
}
DOCUMENT_SCENE_LABELS = {
    "travel": "差旅",
    "hotel": "住宿",
    "transport": "交通",
    "meal": "业务招待",
    "entertainment": "业务招待",
    "marketing": "市场推广",
    "office": "办公用品",
    "meeting": "会务",
    "training": "培训",
    "software": "软件服务",
    "other": "其他票据",
}
DOCUMENT_ASSOCIATION_REVIEW_ACTIONS = {
    "link_to_existing_draft",
    "create_new_claim_from_documents",
}
PERSISTENT_EXPENSE_REVIEW_ACTIONS = {
    "save_draft",
    "next_step",
    *DOCUMENT_ASSOCIATION_REVIEW_ACTIONS,
}
RETURN_REASON_OPTIONS = {
    "missing_attachment": "附件缺失或不清晰",
    "invoice_mismatch": "票据类型/金额与明细不一致",
    "over_policy": "超出制度标准或缺少超标说明",
    "business_explanation": "业务事由/地点/人员信息不完整",
    "duplicate_or_abnormal": "疑似重复或异常票据",
    "approval_question": "审批人需要补充说明",
    "application_info_incomplete": "申请信息不完整",
    "application_business_need_unclear": "业务必要性说明不足",
    "application_budget_basis_missing": "预算测算依据不足",
    "application_policy_mismatch": "制度口径不匹配",
    "application_attachment_needed": "前置材料需补充",
    "application_other": "其他",
}
MAX_CLAIM_NO_RETRY_ATTEMPTS = 3
DOCUMENT_DATE_PATTERN = re.compile(
    r"((?:20\d{2}|19\d{2})[-/年.](?:1[0-2]|0?[1-9])[-/月.]"
    r"(?:3[01]|[12]\d|0?[1-9])日?)"
)
SYSTEM_GENERATED_REASON_PREFIXES = (
    "我上传了",
    "请按当前已识别信息",
    "请把当前上传的票据",
    "请基于当前上传的多张票据",
    "我已核对右侧识别结果",
    "请同步修正逐票据识别结果",
    "我已修改识别信息",
    "查看报销草稿",
    "请解释一下当前这笔报销的合规风险和待补充项",
)
LEADING_REASON_TIME_PATTERNS = (
    re.compile(
        r"^\s*(?:识别事项(?:有)?[：:]\s*)?"
        r"(?:业务发生(?:时间|日期)|费用发生(?:时间|日期)|发生(?:时间|日期)|报销(?:时间|日期)|时间)[：:]?\s*"
        r"(?:19|20)\d{2}[-/年.]\d{1,2}[-/月.]\d{1,2}日?"
        r"(?:\s*(?:至|到|~|～|—|-)\s*(?:19|20)\d{2}[-/年.]\d{1,2}[-/月.]\d{1,2}日?)?"
        r"\s*[，,。；;、]?\s*"
    ),
    re.compile(
        r"^\s*(?:19|20)\d{2}[-/年.]\d{1,2}[-/月.]\d{1,2}日?"
        r"(?:\s*(?:至|到|~|～|—|-)\s*(?:19|20)\d{2}[-/年.]\d{1,2}[-/月.]\d{1,2}日?)?"
        r"\s*[，,。；;、]\s*"
    ),
)
AI_REVIEW_LOOKBACK_DAYS = 90
AI_REVIEW_REPEAT_RISK_WARNING_COUNT = 1
AI_REVIEW_REPEAT_RISK_BLOCK_COUNT = 2
TRAVEL_REVIEW_RELEVANT_EXPENSE_TYPES = {"travel", "hotel", "transport"}
TRAVEL_REVIEW_LONG_DISTANCE_DOCUMENT_TYPES = {"flight_itinerary", "train_ticket"}
TRAVEL_POLICY_CITY_TIERS = {
    "北京": "tier_1",
    "上海": "tier_1",
    "广州": "tier_1",
    "深圳": "tier_1",
    "杭州": "tier_2",
    "南京": "tier_2",
    "苏州": "tier_2",
    "武汉": "tier_2",
    "成都": "tier_2",
    "重庆": "tier_2",
    "西安": "tier_2",
    "天津": "tier_2",
    "宁波": "tier_2",
    "厦门": "tier_2",
    "青岛": "tier_2",
    "长沙": "tier_2",
    "郑州": "tier_2",
    "合肥": "tier_2",
    "济南": "tier_2",
    "沈阳": "tier_2",
    "大连": "tier_2",
    "福州": "tier_2",
    "昆明": "tier_2",
    "海口": "tier_2",
    "三亚": "tier_2",
    "无锡": "tier_2",
    "东莞": "tier_2",
    "佛山": "tier_2",
}
TRAVEL_POLICY_CITY_MATCH_ORDER = tuple(
    sorted(TRAVEL_POLICY_CITY_TIERS.keys(), key=lambda item: len(item), reverse=True)
)
TRAVEL_POLICY_BAND_LABELS = {
    "junior": "P1-P3",
    "mid": "P4-P5",
    "senior": "P6-P7",
    "manager": "M1-M2",
    "executive": "M3及以上 / D序列",
}
TRAVEL_POLICY_HOTEL_LIMITS = {
    "junior": {
        "tier_1": Decimal("450.00"),
        "tier_2": Decimal("380.00"),
        "tier_3": Decimal("320.00"),
    },
    "mid": {
        "tier_1": Decimal("550.00"),
        "tier_2": Decimal("480.00"),
        "tier_3": Decimal("380.00"),
    },
    "senior": {
        "tier_1": Decimal("700.00"),
        "tier_2": Decimal("620.00"),
        "tier_3": Decimal("520.00"),
    },
    "manager": {
        "tier_1": Decimal("900.00"),
        "tier_2": Decimal("820.00"),
        "tier_3": Decimal("720.00"),
    },
    "executive": {
        "tier_1": Decimal("1200.00"),
        "tier_2": Decimal("1000.00"),
        "tier_3": Decimal("900.00"),
    },
}
TRAVEL_POLICY_ALLOWED_TRANSPORT_LEVELS = {
    "junior": {"flight": 1, "train": 1},
    "mid": {"flight": 1, "train": 1},
    "senior": {"flight": 2, "train": 2},
    "manager": {"flight": 3, "train": 3},
    "executive": {"flight": 4, "train": 3},
}
TRAVEL_POLICY_ROUTE_EXCEPTION_KEYWORDS = (
    "中转",
    "转机",
    "经停",
    "改签",
    "多地出差",
    "多城市",
    "多站",
    "异地返程",
    "异地结束",
    "临时变更",
    "继续前往",
    "第二站",
)
TRAVEL_POLICY_STANDARD_EXCEPTION_KEYWORDS = (
    "超标说明",
    "无直达",
    "展会高峰",
    "会议高峰",
    "协议酒店满房",
    "客户指定",
    "临时改签",
    "行程变更",
    "红眼航班",
    "晚到店",
)
TRAVEL_POLICY_FLIGHT_CLASS_PATTERNS = (
    ("头等舱", 4),
    ("公务舱", 3),
    ("商务舱", 3),
    ("超级经济舱", 2),
    ("高端经济舱", 2),
    ("明珠经济舱", 2),
    ("经济舱", 1),
)
TRAVEL_POLICY_TRAIN_CLASS_PATTERNS = (
    ("商务座", 3),
    ("一等座", 2),
    ("软卧", 2),
    ("二等座", 1),
    ("二等卧", 1),
    ("硬卧", 1),
)
TRAVEL_POLICY_HOTEL_NIGHT_PATTERN = re.compile(r"(\d+)\s*(?:晚|间夜)")
