from __future__ import annotations

from dataclasses import dataclass

from .models import PayrollResult


@dataclass(frozen=True)
class PayrollException:
    """工资核算异常，供月度核算服务转换为数据库记录。"""

    employee_id: int | None
    employee_no: str
    employee_name: str
    salary_month: str
    exception_type: str
    severity: str
    message: str


def detect_payroll_exceptions(results: list[PayrollResult]) -> list[PayrollException]:
    """根据工资计算结果识别需要人事或财务复核的异常。"""
    exceptions: list[PayrollException] = []
    for result in results:
        employee = result.employee
        base = {
            "employee_id": None,
            "employee_no": employee.employee_no,
            "employee_name": employee.name,
            "salary_month": result.salary_month,
        }
        if result.base_pay is None:
            exceptions.append(
                PayrollException(
                    **base,
                    exception_type="missing_salary_profile",
                    severity="error",
                    message="员工未配置薪资档案，无法计算应发和实发工资",
                )
            )
        if result.missing_card_count > 0:
            exceptions.append(
                PayrollException(
                    **base,
                    exception_type="missing_card",
                    severity="warning",
                    message=f"缺卡 {result.missing_card_count} 次，已产生扣款 {result.missing_card_deduction:.2f} 元",
                )
            )
        if result.penalized_late_count > 0:
            exceptions.append(
                PayrollException(
                    **base,
                    exception_type="late_penalty",
                    severity="warning",
                    message=f"迟到扣款 {result.penalized_late_count} 次，扣款 {result.late_deduction:.2f} 元",
                )
            )
        if result.remaining_overtime_hours < 0:
            exceptions.append(
                PayrollException(
                    **base,
                    exception_type="negative_remaining_overtime",
                    severity="warning",
                    message=f"请假工时超过加班工时，剩余加班 {result.remaining_overtime_hours:.1f} 小时",
                )
            )
        if result.attendance_days == 0:
            exceptions.append(
                PayrollException(
                    **base,
                    exception_type="empty_attendance",
                    severity="error",
                    message="本月出勤天数为 0，请检查考勤数据或员工状态",
                )
            )
    return exceptions
