from __future__ import annotations

from datetime import date, datetime

from pydantic import BaseModel, Field

from ...database.orm import PayrollJobORM, PayrollResultORM
from ...domain.models import PayrollResult
from ...services import PayrollComputation


class PayrollResultDTO(BaseModel):
    """员工级工资结果响应模型。"""

    name: str
    department: str
    position: str
    attendance_group: str
    salary_month: str
    salary_mode: str
    attendance_days: float
    absence_days: float
    actual_work_hours: float
    punch_overtime_hours: float
    leave_hours: float
    remaining_overtime_hours: float
    workday_overtime_hours: float
    weekend_overtime_hours: float
    holiday_overtime_hours: float
    minor_late_count: int
    major_late_count: int
    penalized_late_count: int
    late_deduction: float
    missing_card_count: int
    missing_card_deduction: float
    total_deduction: float
    base_salary: float | None
    base_pay: float | None
    commission_amount: float
    overtime_rate: float
    weekend_overtime_rate: float
    holiday_overtime_rate: float
    overtime_pay: float
    gross_salary: float | None
    net_salary: float | None
    note: str

    @classmethod
    def from_domain(cls, result: PayrollResult) -> "PayrollResultDTO":
        employee = result.employee
        return cls(
            name=employee.name,
            department=employee.department,
            position=employee.position,
            attendance_group=employee.attendance_group,
            salary_month=result.salary_month,
            salary_mode=result.salary_mode,
            attendance_days=result.attendance_days,
            absence_days=result.absence_days,
            actual_work_hours=result.actual_work_hours,
            punch_overtime_hours=result.punch_overtime_hours,
            leave_hours=result.leave_hours,
            remaining_overtime_hours=result.remaining_overtime_hours,
            workday_overtime_hours=result.workday_overtime_hours,
            weekend_overtime_hours=result.weekend_overtime_hours,
            holiday_overtime_hours=result.holiday_overtime_hours,
            minor_late_count=result.minor_late_count,
            major_late_count=result.major_late_count,
            penalized_late_count=result.penalized_late_count,
            late_deduction=result.late_deduction,
            missing_card_count=result.missing_card_count,
            missing_card_deduction=result.missing_card_deduction,
            total_deduction=result.total_deduction,
            base_salary=result.base_salary,
            base_pay=result.base_pay,
            commission_amount=result.commission_amount,
            overtime_rate=result.overtime_rate,
            weekend_overtime_rate=result.weekend_overtime_rate,
            holiday_overtime_rate=result.holiday_overtime_rate,
            overtime_pay=result.overtime_pay,
            gross_salary=result.gross_salary,
            net_salary=result.net_salary,
            note=result.note,
        )

    @classmethod
    def from_orm_model(cls, result: PayrollResultORM) -> "PayrollResultDTO":
        return cls(
            name=result.name,
            department=result.department,
            position=result.position,
            attendance_group=result.attendance_group,
            salary_month=result.salary_month,
            salary_mode=result.salary_mode,
            attendance_days=result.attendance_days,
            absence_days=result.absence_days,
            actual_work_hours=result.actual_work_hours,
            punch_overtime_hours=result.punch_overtime_hours,
            leave_hours=result.leave_hours,
            remaining_overtime_hours=result.remaining_overtime_hours,
            workday_overtime_hours=result.workday_overtime_hours,
            weekend_overtime_hours=result.weekend_overtime_hours,
            holiday_overtime_hours=result.holiday_overtime_hours,
            minor_late_count=result.minor_late_count,
            major_late_count=result.major_late_count,
            penalized_late_count=result.penalized_late_count,
            late_deduction=result.late_deduction,
            missing_card_count=result.missing_card_count,
            missing_card_deduction=result.missing_card_deduction,
            total_deduction=result.total_deduction,
            base_salary=result.base_salary,
            base_pay=result.base_pay,
            commission_amount=result.commission_amount,
            overtime_rate=result.overtime_rate,
            weekend_overtime_rate=result.weekend_overtime_rate,
            holiday_overtime_rate=result.holiday_overtime_rate,
            overtime_pay=result.overtime_pay,
            gross_salary=result.gross_salary,
            net_salary=result.net_salary,
            note=result.note,
        )


class PayrollResponseBase(BaseModel):
    """Excel 和钉钉计算接口共用的响应结构。"""

    job_id: str
    employee_count: int
    output_file: str | None = None
    download_url: str | None = None
    results: list[PayrollResultDTO]

    @classmethod
    def from_computation(cls, computation: PayrollComputation):
        output_filename = computation.output_filename
        return cls(
            job_id=computation.job_id,
            employee_count=computation.employee_count,
            output_file=computation.output_file,
            download_url=f"/api/payroll/download/{output_filename}" if output_filename else None,
            results=[PayrollResultDTO.from_domain(result) for result in computation.results],
        )


class ExcelPayrollResponse(PayrollResponseBase):
    pass


class DingTalkPayrollRequest(BaseModel):
    """钉钉实时计算请求参数。"""

    user_ids: list[str] = Field(..., description="钉钉员工 userId 列表")
    start_date: date
    end_date: date
    config_path: str | None = None
    export_excel: bool = True


class DingTalkPayrollResponse(PayrollResponseBase):
    pass


class PayrollJobResponse(BaseModel):
    """已落库工资计算任务的查询响应。"""

    job_id: str
    source_type: str
    status: str
    input_file: str | None
    output_file: str | None
    employee_count: int
    error_message: str | None
    created_at: datetime
    updated_at: datetime
    results: list[PayrollResultDTO]

    @classmethod
    def from_orm_model(cls, job: PayrollJobORM) -> "PayrollJobResponse":
        return cls(
            job_id=job.id,
            source_type=job.source_type,
            status=job.status,
            input_file=job.input_file,
            output_file=job.output_file,
            employee_count=job.employee_count,
            error_message=job.error_message,
            created_at=job.created_at,
            updated_at=job.updated_at,
            results=[PayrollResultDTO.from_orm_model(result) for result in job.results],
        )
