from __future__ import annotations

import re
from dataclasses import dataclass

from ..core.logger import AppLogger
from ..database.orm import EmployeeORM
from ..repositories import EmployeeRepository

logger = AppLogger.get_logger(__name__)

VALID_EMPLOYMENT_STATUS = {"active", "inactive"}
EMPLOYEE_NO_PREFIX = "ZA"
EMPLOYEE_NO_WIDTH = 4


@dataclass(frozen=True)
class EmployeePage:
    """员工分页结果。"""

    items: list[EmployeeORM]
    total: int
    page: int
    page_size: int


class EmployeeService:
    """员工应用服务：处理员工档案维护校验。"""

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

    def preview_next_employee_no(self) -> str:
        """预览下一个员工编号，实际新增时仍以后端最终生成为准。"""
        employee_no = self._next_employee_no()
        logger.info("预览下一个员工编号 employee_no=%s", employee_no)
        return employee_no

    def create_employee(
        self,
        *,
        employee_no: str = "",
        name: str,
        dingtalk_user_id: str = "",
        department: str = "",
        position: str = "",
        phone: str = "",
        employment_status: str = "active",
        remark: str = "",
    ) -> EmployeeORM:
        employee_no = self._next_employee_no()
        name = _required(name, "员工姓名")
        employment_status = _valid_status(employment_status)
        if self.repository.get_by_employee_no(employee_no):
            raise ValueError("员工编号已存在")

        employee = self.repository.create_employee(
            employee_no=employee_no,
            name=name,
            dingtalk_user_id=dingtalk_user_id.strip(),
            department=department.strip(),
            position=position.strip(),
            phone=phone.strip(),
            employment_status=employment_status,
            remark=remark.strip(),
        )
        logger.info("员工创建成功 employee_id=%s employee_no=%s name=%s", employee.id, employee.employee_no, employee.name)
        return employee

    def update_employee(
        self,
        employee_id: int,
        *,
        employee_no: str = "",
        name: str | None = None,
        dingtalk_user_id: str | None = None,
        department: str | None = None,
        position: str | None = None,
        phone: str | None = None,
        employment_status: str | None = None,
        remark: str | None = None,
    ) -> EmployeeORM:
        current = self.repository.require_by_id(employee_id)
        employee_no = current.employee_no
        clean_name = _required(name if name is not None else current.name, "员工姓名")
        clean_status = _valid_status(employment_status if employment_status is not None else current.employment_status)

        employee = self.repository.update_employee(
            employee_id,
            employee_no=employee_no,
            name=clean_name,
            dingtalk_user_id=_clean_update_value(dingtalk_user_id, current.dingtalk_user_id),
            department=_clean_update_value(department, current.department),
            position=_clean_update_value(position, current.position),
            phone=_clean_update_value(phone, current.phone),
            employment_status=clean_status,
            remark=_clean_update_value(remark, current.remark),
        )
        logger.info("员工更新成功 employee_id=%s employee_no=%s name=%s", employee.id, employee.employee_no, employee.name)
        return employee

    def get_employee(self, employee_id: int) -> EmployeeORM:
        employee = self.repository.require_by_id(employee_id)
        logger.info("查询员工详情成功 employee_id=%s employee_no=%s", employee.id, employee.employee_no)
        return employee

    def list_employees(
        self,
        *,
        keyword: str | None = None,
        employee_keyword: str | None = None,
        organization_keyword: str | None = None,
        employment_status: str | None = None,
    ) -> list[EmployeeORM]:
        clean_status = _clean_optional(employment_status)
        if clean_status is not None:
            clean_status = _valid_status(clean_status)
        employees = self.repository.list_employees(
            keyword=_clean_optional(keyword),
            employee_keyword=_clean_optional(employee_keyword),
            organization_keyword=_clean_optional(organization_keyword),
            employment_status=clean_status,
        )
        logger.info("查询员工列表成功 count=%s", len(employees))
        return employees

    def list_employees_page(
        self,
        *,
        page: int,
        page_size: int,
        keyword: str | None = None,
        employee_keyword: str | None = None,
        organization_keyword: str | None = None,
        employment_status: str | None = None,
    ) -> EmployeePage:
        clean_status = _clean_optional(employment_status)
        if clean_status is not None:
            clean_status = _valid_status(clean_status)
        safe_page = max(page, 1)
        safe_page_size = min(max(page_size, 1), 100)
        employees, total = self.repository.list_employees_page(
            page=safe_page,
            page_size=safe_page_size,
            keyword=_clean_optional(keyword),
            employee_keyword=_clean_optional(employee_keyword),
            organization_keyword=_clean_optional(organization_keyword),
            employment_status=clean_status,
        )
        logger.info("分页查询员工列表成功 total=%s page=%s page_size=%s", total, safe_page, safe_page_size)
        return EmployeePage(items=employees, total=total, page=safe_page, page_size=safe_page_size)

    def _next_employee_no(self) -> str:
        existing_numbers = self.repository.list_employee_numbers_by_prefix(EMPLOYEE_NO_PREFIX)
        pattern = re.compile(rf"^{re.escape(EMPLOYEE_NO_PREFIX)}(\d+)$")
        used_numbers = {
            int(match.group(1))
            for employee_no in existing_numbers
            if (match := pattern.match(employee_no))
        }
        number = 1
        while number in used_numbers:
            number += 1
        return f"{EMPLOYEE_NO_PREFIX}{number:0{EMPLOYEE_NO_WIDTH}d}"


def _required(value: str, label: str) -> str:
    stripped = value.strip()
    if not stripped:
        raise ValueError(f"{label}不能为空")
    return stripped


def _clean_update_value(value: str | None, fallback: str) -> str:
    if value is None:
        return fallback
    return value.strip()


def _valid_status(value: str) -> str:
    stripped = value.strip() or "active"
    if stripped not in VALID_EMPLOYMENT_STATUS:
        raise ValueError("员工状态只能是 active 或 inactive")
    return stripped


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