# -*- coding: utf-8 -*-
"""业务层 · 用户管理服务（角色分配提权防护 + 建号联动默认身份）。"""
from __future__ import annotations

from fastapi import HTTPException

from ..infrastructure.repositories import Database

# 业务角色 → 端口映射（与领域规则一致）
_PORT_FOR_ROLE = {
    "opc_member": "opc", "carrier": "carrier", "enterprise": "enterprise",
    "provider": "provider", "government": "government", "operator": "operator",
    "investor": "investor", "developer": "developer",
}


class UserAdminService:
    """运营端账号/角色管理。"""

    def __init__(self, db: Database):
        self.db = db

    async def _validate_role_assignment(self, actor: dict, role: str, sub_role: str | None) -> None:
        """白名单 + 提权防护：拒绝非法角色组合，及无权者创建/提升特权角色。"""
        key = role if not sub_role else f"{role}|{sub_role}"
        if not await self.db.roles.role_exists(role):
            raise HTTPException(status_code=400, detail=f"无效角色: {role}")
        if sub_role and not await self.db.roles.role_exists(f"{role}|{sub_role}"):
            raise HTTPException(status_code=400, detail=f"无效角色组合: {key}")
        if "action:role.grant_perm" in await self.db.roles.permissions_for(role, sub_role) \
                and "action:role.grant_perm" not in actor.get("permissions", []):
            raise HTTPException(status_code=403, detail="无权创建/分配特权角色（仅超级管理员）")

    async def create_user(self, req, actor: dict) -> dict:
        """创建账号 + 自动创建默认端口身份（含提权防护）。"""
        if not req.username.strip() or not req.password.strip():
            raise HTTPException(status_code=400, detail="账号与密码必填")
        if await self.db.users.get_by_username(req.username) is not None:
            raise HTTPException(status_code=400, detail="账号已存在")
        await self._validate_role_assignment(actor, req.role, req.sub_role)
        user = await self.db.users.create(
            req.username, req.password, nickname=req.nickname,
            role=req.role, sub_role=req.sub_role, org_id=req.org_id, region_id=req.region_id,
        )
        await self.db.identities.create(
            user["id"], port=_PORT_FOR_ROLE.get(req.role, "opc"), role=req.role,
            sub_role=req.sub_role, org_id=req.org_id, region_id=req.region_id,
            name=req.nickname or req.username,
        )
        return user

    async def set_user_role(self, actor: dict, user_id: str, role: str, sub_role: str, org_id: str, region_id: str) -> dict:
        """分配角色（含提权防护，同步主身份并失效旧令牌）。"""
        await self._validate_role_assignment(actor, role, sub_role)
        return await self.db.users.set_role(user_id, role, sub_role, org_id, region_id)
