from __future__ import annotations

from ..core.logger import AppLogger
from ..database.orm import SalaryProfileORM
from ..domain.models import EmployeePayConfig
from ..repositories import EmployeeRepository, SalaryProfileRepository

logger = AppLogger.get_logger(__name__)


VALID_SALARY_MODES = {"monthly", "hourly", "piecework", "probation"}
VALID_PROBATION_TYPES = {"ratio", "fixed"}


class SalaryProfileService:
    """薪资档案应用服务：维护不同薪资模式和独立加班费单价。"""

    def __init__(self, repository: SalaryProfileRepository, employee_repository: EmployeeRepository):
        self.repository = repository
        self.employee_repository = employee_repository

    def upsert_profile(
        self,
        *,
        employee_id: int,
        salary_mode: str,
        base_salary: float,
        hourly_rate: float,
        piece_quantity: float,
        piece_unit_price: float,
        probation_type: str,
        probation_ratio: float,
        probation_salary: float,
        commission_amount: float,
        overtime_rate: float,
        weekend_overtime_rate: float,
        holiday_overtime_rate: float,
        effective_month: str = "",
        remark: str = "",
    ) -> SalaryProfileORM:
        self.employee_repository.require_by_id(employee_id)
        normalized_salary_mode = salary_mode.strip() or "monthly"
        if normalized_salary_mode not in VALID_SALARY_MODES:
            raise ValueError("薪资模式不合法")
        normalized_probation_type = probation_type.strip() or "ratio"
        if normalized_probation_type not in VALID_PROBATION_TYPES:
            raise ValueError("试用期计算方式不合法")
        profile = self.repository.upsert_profile(
            employee_id=employee_id,
            salary_mode=normalized_salary_mode,
            base_salary=_non_negative(base_salary, "基础工资"),
            hourly_rate=_non_negative(hourly_rate, "计时小时单价"),
            piece_quantity=_non_negative(piece_quantity, "计件数量"),
            piece_unit_price=_non_negative(piece_unit_price, "计件单价"),
            probation_type=normalized_probation_type,
            probation_ratio=_non_negative(probation_ratio, "试用期比例") or 1,
            probation_salary=_non_negative(probation_salary, "试用期固定工资"),
            commission_amount=_non_negative(commission_amount, "提成费用"),
            overtime_rate=_non_negative(overtime_rate, "工作日加班费小时单价"),
            weekend_overtime_rate=_non_negative(weekend_overtime_rate, "周末加班费小时单价"),
            holiday_overtime_rate=_non_negative(holiday_overtime_rate, "节假日加班费小时单价"),
            effective_month=effective_month.strip(),
            remark=remark.strip(),
        )
        logger.info(
            "薪资档案保存成功 employee_id=%s salary_mode=%s base_salary=%s commission=%s overtime_rate=%s",
            employee_id,
            profile.salary_mode,
            profile.base_salary,
            profile.commission_amount,
            profile.overtime_rate,
        )
        return profile

    def list_profiles(self, *, keyword: str | None = None) -> list[SalaryProfileORM]:
        profiles = self.repository.list_profiles(keyword=_clean_optional(keyword))
        logger.info("查询薪资档案成功 count=%s", len(profiles))
        return profiles

    def active_pay_config_by_employee_name(self) -> dict[str, EmployeePayConfig]:
        """生成工资计算器使用的员工薪资配置，按员工姓名匹配考勤表。"""
        profiles = self.repository.list_active_profiles()
        result: dict[str, EmployeePayConfig] = {}
        for profile in profiles:
            employee = profile.employee
            if not employee.name:
                continue
            result[employee.name] = EmployeePayConfig(
                salary_mode=profile.salary_mode,
                base_salary=profile.base_salary,
                hourly_rate=profile.hourly_rate,
                piece_quantity=profile.piece_quantity,
                piece_unit_price=profile.piece_unit_price,
                probation_type=profile.probation_type,
                probation_ratio=profile.probation_ratio,
                probation_salary=profile.probation_salary,
                commission_amount=profile.commission_amount,
                overtime_rate=profile.overtime_rate,
                weekend_overtime_rate=profile.weekend_overtime_rate,
                holiday_overtime_rate=profile.holiday_overtime_rate,
            )
        logger.info("薪资档案转换为工资计算配置 count=%s", len(result))
        return result


def _non_negative(value: float, label: str) -> float:
    number = float(value or 0)
    if number < 0:
        raise ValueError(f"{label}不能小于0")
    return number


def _clean_optional(value: str | None) -> str | None:
    if value is None:
        return None
    stripped = value.strip()
    return stripped or None
