from __future__ import annotations

import json
from dataclasses import dataclass, field
from pathlib import Path

from ..domain.models import EmployeePayConfig


@dataclass(frozen=True)
class AttendanceRules:
    """考勤规则配置，默认值来自当前工资计算约定。"""

    on_work_time: str = "08:30"
    off_work_time: str = "17:00"
    overtime_round_minutes: int = 60
    standard_daily_hours: float = 8
    minor_late_minutes: int = 5
    minor_late_free_times: int = 3
    late_penalty: float = 30
    missing_card_penalty: float = 20
    weekend_days: tuple[int, ...] = (5, 6)
    legal_holidays: tuple[str, ...] = ()
    leave_keywords: tuple[str, ...] = (
        "调休",
        "请假",
        "事假",
        "病假",
        "年假",
        "婚假",
        "产假",
        "陪产假",
        "丧假",
    )


@dataclass(frozen=True)
class PayrollRules:
    default_overtime_rate: float = 0
    default_weekend_overtime_rate: float = 0
    default_holiday_overtime_rate: float = 0
    employees: dict[str, EmployeePayConfig] = field(default_factory=dict)


@dataclass(frozen=True)
class AppConfig:
    attendance: AttendanceRules = field(default_factory=AttendanceRules)
    payroll: PayrollRules = field(default_factory=PayrollRules)


def load_config(path: str | Path | None) -> AppConfig:
    """加载可选 JSON 配置；未传路径时使用内置默认规则。"""
    if not path:
        return AppConfig()

    raw = json.loads(Path(path).read_text(encoding="utf-8"))
    attendance_raw = raw.get("attendance", {})
    payroll_raw = raw.get("payroll", {})
    employees_raw = payroll_raw.get("employees", {})

    attendance = AttendanceRules(
        on_work_time=attendance_raw.get("on_work_time", AttendanceRules.on_work_time),
        off_work_time=attendance_raw.get("off_work_time", AttendanceRules.off_work_time),
        overtime_round_minutes=int(
            attendance_raw.get("overtime_round_minutes", AttendanceRules.overtime_round_minutes)
        ),
        standard_daily_hours=float(
            attendance_raw.get("standard_daily_hours", AttendanceRules.standard_daily_hours)
        ),
        minor_late_minutes=int(
            attendance_raw.get("minor_late_minutes", AttendanceRules.minor_late_minutes)
        ),
        minor_late_free_times=int(
            attendance_raw.get("minor_late_free_times", AttendanceRules.minor_late_free_times)
        ),
        late_penalty=float(attendance_raw.get("late_penalty", AttendanceRules.late_penalty)),
        missing_card_penalty=float(
            attendance_raw.get("missing_card_penalty", AttendanceRules.missing_card_penalty)
        ),
        weekend_days=tuple(int(item) for item in attendance_raw.get("weekend_days", AttendanceRules.weekend_days)),
        legal_holidays=tuple(attendance_raw.get("legal_holidays", AttendanceRules.legal_holidays)),
        leave_keywords=tuple(attendance_raw.get("leave_keywords", AttendanceRules.leave_keywords)),
    )

    employees = {
        name: EmployeePayConfig(
            salary_mode=values.get("salary_mode", "monthly") or "monthly",
            base_salary=_optional_float(values.get("base_salary")),
            hourly_rate=float(values.get("hourly_rate", 0) or 0),
            piece_quantity=float(values.get("piece_quantity", 0) or 0),
            piece_unit_price=float(values.get("piece_unit_price", 0) or 0),
            probation_type=values.get("probation_type", "ratio") or "ratio",
            probation_ratio=float(values.get("probation_ratio", 1) or 1),
            probation_salary=_optional_float(values.get("probation_salary")),
            commission_amount=float(values.get("commission_amount", 0) or 0),
            overtime_rate=_optional_float(values.get("overtime_rate")),
            weekend_overtime_rate=_optional_float(values.get("weekend_overtime_rate")),
            holiday_overtime_rate=_optional_float(values.get("holiday_overtime_rate")),
        )
        for name, values in employees_raw.items()
    }

    payroll = PayrollRules(
        default_overtime_rate=float(payroll_raw.get("default_overtime_rate", 0)),
        default_weekend_overtime_rate=float(payroll_raw.get("default_weekend_overtime_rate", 0)),
        default_holiday_overtime_rate=float(payroll_raw.get("default_holiday_overtime_rate", 0)),
        employees=employees,
    )
    return AppConfig(attendance=attendance, payroll=payroll)


def _optional_float(value: object) -> float | None:
    if value in (None, ""):
        return None
    return float(value)
