from __future__ import annotations

import re

from ..core.logger import AppLogger
from ..database.orm import DepartmentORM, PositionORM
from ..repositories import OrganizationRepository

logger = AppLogger.get_logger(__name__)

DEFAULT_ORGANIZATION = [
    {
        "code": "ORG001",
        "name": "总经办",
        "parent": None,
        "positions": ["总经理", "副总经理", "总经理助理"],
    },
    {
        "code": "ORG002",
        "name": "行政人事部",
        "parent": None,
        "positions": ["人事经理", "人事专员"],
    },
    {
        "code": "ORG003",
        "name": "财务部",
        "parent": None,
        "positions": ["财务", "出纳专员"],
    },
    {
        "code": "ORG004",
        "name": "订单部",
        "parent": None,
        "positions": ["销售助理", "订单助理"],
    },
    {
        "code": "ORG005",
        "name": "工程部",
        "parent": None,
        "positions": [],
        "remark": "系统根据工程部子部门自动补齐的父级部门",
    },
    {
        "code": "ORG006",
        "name": "工程部-安装队",
        "parent": "工程部",
        "positions": ["经理助理", "安装师傅", "项目经理"],
    },
    {
        "code": "ORG007",
        "name": "工程部-项目预算",
        "parent": "工程部",
        "positions": ["项目预算"],
    },
    {
        "code": "ORG008",
        "name": "杭州运营中心",
        "parent": None,
        "positions": [],
        "remark": "系统根据杭州运营中心子部门自动补齐的父级部门",
    },
    {
        "code": "ORG009",
        "name": "杭州运营中心-销售部",
        "parent": "杭州运营中心",
        "positions": ["销售总监", "销售"],
    },
    {
        "code": "ORG010",
        "name": "华南运营中心",
        "parent": None,
        "positions": ["销售总监"],
    },
    {
        "code": "ORG011",
        "name": "华中运营中心",
        "parent": None,
        "positions": ["销售总监"],
    },
    {
        "code": "ORG012",
        "name": "生产中心",
        "parent": None,
        "positions": ["机械工程师"],
    },
    {
        "code": "ORG013",
        "name": "生产中心-采购部",
        "parent": "生产中心",
        "positions": ["采购"],
    },
    {
        "code": "ORG014",
        "name": "生产中心-仓库",
        "parent": "生产中心",
        "positions": ["仓库", "仓库物料员"],
    },
    {
        "code": "ORG015",
        "name": "生产中心-品管部",
        "parent": "生产中心",
        "positions": ["品管"],
    },
    {
        "code": "ORG016",
        "name": "生产中心-生产部",
        "parent": "生产中心",
        "positions": ["焊接师傅", "普工", "技工"],
    },
    {
        "code": "ORG017",
        "name": "西南运营中心",
        "parent": None,
        "positions": ["销售总监"],
    },
    {
        "code": "ORG018",
        "name": "西南运营中心-办事处",
        "parent": "西南运营中心",
        "positions": ["经理助理"],
    },
    {
        "code": "ORG019",
        "name": "西南运营中心-销售部",
        "parent": "西南运营中心",
        "positions": ["销售工程师"],
    },
]
DEFAULT_DEPARTMENTS = [item["name"] for item in DEFAULT_ORGANIZATION]


class OrganizationService:
    """组织架构服务：维护部门、岗位和二者的上下级关系。"""

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

    def ensure_default_departments(self) -> int:
        """启动时补齐默认组织架构，包含部门树和部门岗位。"""
        department_created = 0
        department_updated = 0
        position_created = 0
        position_updated = 0
        seeded_departments: dict[str, DepartmentORM] = {}

        for index, item in enumerate(DEFAULT_ORGANIZATION, start=1):
            parent_name = item["parent"]
            parent = seeded_departments.get(parent_name) if parent_name else None
            if parent is None and parent_name:
                parent = self.repository.get_department_by_name(parent_name)
            existing = self.repository.get_department_by_name(item["name"])
            department_code = self._usable_department_code(str(item["code"]), existing)
            payload = {
                "parent_id": parent.id if parent else None,
                "department_code": department_code,
                "name": item["name"],
                "sort_order": index,
                "is_active": True,
                "remark": item.get("remark", "系统初始化部门"),
            }
            if existing is None:
                department = self.repository.create_department(**payload)
                department_created += 1
            elif _department_changed(existing, payload):
                department = self.repository.update_department(existing.id, **payload)
                department_updated += 1
            else:
                department = existing
            seeded_departments[department.name] = department

        position_index = 1
        for item in DEFAULT_ORGANIZATION:
            department = seeded_departments[item["name"]]
            for position_sort, position_name in enumerate(item["positions"], start=1):
                preferred_code = f"POS{position_index:03d}"
                existing_position = self.repository.get_position_by_department_and_name(
                    department.id,
                    position_name,
                )
                payload = {
                    "department_id": department.id,
                    "position_code": self._usable_position_code(preferred_code, existing_position),
                    "name": position_name,
                    "sort_order": position_sort,
                    "is_active": True,
                    "remark": "系统初始化岗位",
                }
                if existing_position is None:
                    self.repository.create_position(**payload)
                    position_created += 1
                elif _position_changed(existing_position, payload):
                    self.repository.update_position(existing_position.id, **payload)
                    position_updated += 1
                position_index += 1

        logger.info(
            "默认组织架构初始化完成 department_created=%s department_updated=%s position_created=%s position_updated=%s",
            department_created,
            department_updated,
            position_created,
            position_updated,
        )
        return department_created + position_created

    def list_departments(self, *, active_only: bool = False, keyword: str | None = None) -> list[DepartmentORM]:
        departments = self.repository.list_departments(active_only=active_only, keyword=_clean_optional(keyword))
        logger.info("查询部门成功 count=%s active_only=%s", len(departments), active_only)
        return departments

    def create_department(self, **values) -> DepartmentORM:
        payload = self._validated_department_values(values)
        if self.repository.get_department_by_code(payload["department_code"]) is not None:
            raise ValueError("部门编码已存在")
        if self.repository.get_department_by_name(payload["name"]) is not None:
            raise ValueError("部门名称已存在")
        department = self.repository.create_department(**payload)
        logger.info("新增部门成功 department_id=%s name=%s", department.id, department.name)
        return department

    def update_department(self, department_id: int, **values) -> DepartmentORM:
        payload = self._validated_department_values(values, department_id=department_id)
        by_code = self.repository.get_department_by_code(payload["department_code"])
        if by_code is not None and by_code.id != department_id:
            raise ValueError("部门编码已存在")
        by_name = self.repository.get_department_by_name(payload["name"])
        if by_name is not None and by_name.id != department_id:
            raise ValueError("部门名称已存在")
        department = self.repository.update_department(department_id, **payload)
        logger.info("更新部门成功 department_id=%s name=%s", department.id, department.name)
        return department

    def list_positions(
        self,
        *,
        department_id: int | None = None,
        active_only: bool = False,
        keyword: str | None = None,
    ) -> list[PositionORM]:
        if department_id:
            self.repository.require_department(department_id)
        positions = self.repository.list_positions(
            department_id=department_id,
            active_only=active_only,
            keyword=_clean_optional(keyword),
        )
        logger.info("查询岗位成功 count=%s department_id=%s", len(positions), department_id)
        return positions

    def create_position(self, **values) -> PositionORM:
        payload = self._validated_position_values(values)
        if self.repository.get_position_by_code(payload["position_code"]) is not None:
            raise ValueError("岗位编码已存在")
        self._ensure_position_name_available(payload["department_id"], payload["name"])
        position = self.repository.create_position(**payload)
        logger.info("新增岗位成功 position_id=%s name=%s", position.id, position.name)
        return position

    def update_position(self, position_id: int, **values) -> PositionORM:
        current = self.repository.require_position(position_id)
        payload = self._validated_position_values(values, current=current)
        by_code = self.repository.get_position_by_code(payload["position_code"])
        if by_code is not None and by_code.id != position_id:
            raise ValueError("岗位编码已存在")
        self._ensure_position_name_available(payload["department_id"], payload["name"], position_id=position_id)
        position = self.repository.update_position(position_id, **payload)
        logger.info("更新岗位成功 position_id=%s name=%s", position.id, position.name)
        return position

    def _validated_department_values(self, values: dict, department_id: int | None = None) -> dict:
        parent_id = values.get("parent_id")
        parent_id = int(parent_id) if parent_id not in (None, "", 0) else None
        if parent_id:
            if parent_id == department_id:
                raise ValueError("父级部门不能选择自己")
            self.repository.require_department(parent_id)
        department_code = str(values.get("department_code") or "").strip()
        name = str(values.get("name") or "").strip()
        if not department_code:
            raise ValueError("部门编码不能为空")
        if not name:
            raise ValueError("部门名称不能为空")
        return {
            "parent_id": parent_id,
            "department_code": department_code,
            "name": name,
            "sort_order": int(values.get("sort_order") or 0),
            "is_active": bool(values.get("is_active", True)),
            "remark": str(values.get("remark") or "").strip(),
        }

    def _validated_position_values(self, values: dict, current: PositionORM | None = None) -> dict:
        department_id = int(values.get("department_id") or 0)
        self.repository.require_department(department_id)
        position_code = str(values.get("position_code") or "").strip()
        name = str(values.get("name") or "").strip()
        if not position_code:
            position_code = current.position_code if current else self._next_position_code()
        if not name:
            raise ValueError("岗位名称不能为空")
        return {
            "department_id": department_id,
            "position_code": position_code,
            "name": name,
            "sort_order": int(values.get("sort_order") or 0),
            "is_active": bool(values.get("is_active", True)),
            "remark": str(values.get("remark") or "").strip(),
        }

    def _ensure_position_name_available(
        self,
        department_id: int,
        name: str,
        *,
        position_id: int | None = None,
    ) -> None:
        by_name = self.repository.get_position_by_department_and_name(department_id, name)
        if by_name is not None and by_name.id != position_id:
            raise ValueError("该部门下岗位名称已存在")

    def _usable_department_code(self, preferred_code: str, existing: DepartmentORM | None = None) -> str:
        owner = self.repository.get_department_by_code(preferred_code)
        if owner is None or (existing is not None and owner.id == existing.id):
            return preferred_code
        if existing is not None:
            return existing.department_code
        return self._next_department_code()

    def _usable_position_code(self, preferred_code: str, existing: PositionORM | None = None) -> str:
        owner = self.repository.get_position_by_code(preferred_code)
        if owner is None or (existing is not None and owner.id == existing.id):
            return preferred_code
        if existing is not None:
            return existing.position_code
        return self._next_position_code()

    def _next_department_code(self) -> str:
        return _next_code(
            [department.department_code for department in self.repository.list_departments(active_only=False)],
            "ORG",
        )

    def _next_position_code(self) -> str:
        return _next_code(
            [position.position_code for position in self.repository.list_positions(active_only=False)],
            "POS",
        )


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


def _next_code(existing_codes: list[str], prefix: str) -> str:
    pattern = re.compile(rf"^{re.escape(prefix)}(\d+)$")
    used_numbers = {
        int(match.group(1))
        for code in existing_codes
        if (match := pattern.match(code))
    }
    number = 1
    while number in used_numbers:
        number += 1
    return f"{prefix}{number:03d}"


def _department_changed(department: DepartmentORM, payload: dict) -> bool:
    return any(
        [
            department.parent_id != payload["parent_id"],
            department.department_code != payload["department_code"],
            department.name != payload["name"],
            department.sort_order != payload["sort_order"],
            department.is_active != payload["is_active"],
            department.remark != payload["remark"],
        ]
    )


def _position_changed(position: PositionORM, payload: dict) -> bool:
    return any(
        [
            position.department_id != payload["department_id"],
            position.position_code != payload["position_code"],
            position.name != payload["name"],
            position.sort_order != payload["sort_order"],
            position.is_active != payload["is_active"],
            position.remark != payload["remark"],
        ]
    )
