"""认证服务（与 npm AuthService 对齐）。"""
import urllib.parse
from typing import Any, Optional

from .base_client import BaseClient
from .types import (
    ClientConfig,
    RequestOptions,
    TokenStorage,
    LoginResponse,
    LoginCredentials,
    WechatLoginCredentials,
    RegisterRequest,
    TemporaryTokenRequest,
    TemporaryTokenResponse,
    VerifyTemporaryTokenRequest,
    VerifyTemporaryTokenResponse,
    TokenInfoResponse,
    RevokeTokenResponse,
)


class AuthService(BaseClient):
    service_path = "auth"

    def __init__(
        self,
        config: ClientConfig,
        token_storage: Optional[TokenStorage] = None,
    ) -> None:
        super().__init__(config, token_storage=token_storage)

    @property
    def service_name(self) -> str:
        return "auth"

    def login(
        self,
        identifier: str,
        password: str,
        project_id: int = 0,
        options: Optional[RequestOptions] = None,
    ) -> LoginResponse:
        """用户登录（表单格式，兼容旧版）。"""
        body = urllib.parse.urlencode({
            "grant_type": "password",
            "username": identifier,
            "password": password,
        })
        opts = options or RequestOptions()
        headers = dict(opts.headers or {})
        headers["Content-Type"] = "application/x-www-form-urlencoded"
        params = dict(opts.params or {})
        params["project_id"] = project_id
        return self._form_login_request(
            "/login",
            RequestOptions(
                method="POST",
                headers=headers,
                params=params,
                body=body,
                user_context=opts.user_context,
                project_id=opts.project_id,
                org_id=opts.org_id,
                app_id=opts.app_id,
            ),
        )

    def _form_login_request(
        self,
        path: str,
        options: RequestOptions,
    ) -> LoginResponse:
        """发表单格式登录请求，返回 LoginResponse。"""
        url, headers, params = self._prepare_request(path, options)
        headers.update(dict(options.headers or {}))
        if options.params:
            params.update(options.params)

        resp = self.session.post(
            url,
            headers=headers,
            params=params,
            data=options.body,
            timeout=self._timeout,
        )
        resp.raise_for_status()
        data = resp.json()
        if not data.get("success", False):
            raise Exception(
                f"[{self.service_name}服务] {data.get('message', '业务请求失败')} (路径: {path})"
            )
        inner = data.get("data", {})
        access_token = data.get("access_token") or inner.get("access_token", "")
        return LoginResponse(
            access_token=access_token,
            token_type=inner.get("token_type", "Bearer"),
            expires_at=inner.get("expires_at", ""),
            project_id=inner.get("project_id", 0),
            org_id=inner.get("org_id"),
            app_id=inner.get("app_id"),
        )

    def login_json(
        self,
        credentials: LoginCredentials,
        project_id: int = 0,
        options: Optional[RequestOptions] = None,
    ) -> LoginResponse:
        """用户登录（JSON 格式）。"""
        opts = options or RequestOptions()
        headers = dict(opts.headers or {})
        headers["Content-Type"] = "application/json"
        headers["x-project-id"] = str(project_id)
        body = {
            "username": credentials.username,
            "password": credentials.password,
            "org_id": credentials.org_id,
            "app_id": credentials.app_id,
        }
        data = self.request("/login", RequestOptions(
            method="POST",
            headers=headers,
            params=opts.params,
            body=body,
            user_context=opts.user_context,
            project_id=opts.project_id,
            org_id=opts.org_id,
            app_id=opts.app_id,
        ))
        return self._to_login_response(data)

    def _to_login_response(self, data: Any) -> LoginResponse:
        if isinstance(data, LoginResponse):
            return data
        return LoginResponse(
            access_token=data.get("access_token", ""),
            token_type=data.get("token_type", "Bearer"),
            expires_at=data.get("expires_at", ""),
            project_id=data.get("project_id", 0),
            org_id=data.get("org_id"),
            app_id=data.get("app_id"),
        )

    def wechat_mini_program_login(
        self,
        credentials: WechatLoginCredentials,
        project_id: int = 0,
        options: Optional[RequestOptions] = None,
    ) -> LoginResponse:
        """微信小程序登录。"""
        opts = options or RequestOptions()
        headers = dict(opts.headers or {})
        headers["Content-Type"] = "application/json"
        headers["x-project-id"] = str(project_id)
        body = {
            "code": credentials.code,
            "phone_code": credentials.phone_code,
            "org_id": credentials.org_id,
            "app_id": credentials.app_id,
        }
        data = self.request("/wxmp/login", RequestOptions(
            method="POST",
            headers=headers,
            params=opts.params,
            body=body,
            user_context=opts.user_context,
            project_id=opts.project_id,
            org_id=opts.org_id,
            app_id=opts.app_id,
        ))
        return self._to_login_response(data)

    def register(
        self,
        data: RegisterRequest,
        project_id: int = 0,
        options: Optional[RequestOptions] = None,
    ) -> LoginResponse:
        """用户注册。"""
        opts = options or RequestOptions()
        headers = dict(opts.headers or {})
        headers["Content-Type"] = "application/json"
        headers["x-project-id"] = str(project_id)
        body = {
            "username": data.username,
            "email": data.email,
            "password": data.password,
            "name": data.name,
            "phone": data.phone,
            "org_id": data.org_id,
            "app_id": data.app_id,
        }
        raw = self.request("/register", RequestOptions(
            method="POST",
            headers=headers,
            params=opts.params,
            body=body,
            user_context=opts.user_context,
            project_id=opts.project_id,
            org_id=opts.org_id,
            app_id=opts.app_id,
        ))
        return self._to_login_response(raw)

    def create_temporary_token(
        self,
        request: Optional[TemporaryTokenRequest] = None,
        options: Optional[RequestOptions] = None,
    ) -> TemporaryTokenResponse:
        """签发临时令牌。"""
        req = request or TemporaryTokenRequest(expires_in=300)
        body = {"expires_in": req.expires_in}
        return self.request("/temporary-token", RequestOptions(
            method="POST",
            body=body,
        ))

    def verify_temporary_token(
        self,
        request: VerifyTemporaryTokenRequest,
        options: Optional[RequestOptions] = None,
    ) -> VerifyTemporaryTokenResponse:
        """验证临时令牌。"""
        return self.request("/verify-temporary-token", RequestOptions(
            method="POST",
            body={"temporary_token": request.temporary_token},
        ))

    def logout(
        self,
        token: str,
        options: Optional[RequestOptions] = None,
    ) -> None:
        """用户登出。"""
        opts = options or RequestOptions()
        headers = dict(opts.headers or {})
        headers["Authorization"] = f"Bearer {token}"
        self.request("/logout", RequestOptions(
            method="POST",
            headers=headers,
            params=opts.params,
            user_context=opts.user_context,
            project_id=opts.project_id,
            org_id=opts.org_id,
            app_id=opts.app_id,
        ))

    def get_token_info(
        self,
        options: Optional[RequestOptions] = None,
    ) -> TokenInfoResponse:
        """获取当前令牌信息。"""
        return self.request("/token/info", RequestOptions(method="GET"))

    def revoke_token(
        self,
        token: Optional[str] = None,
        options: Optional[RequestOptions] = None,
    ) -> RevokeTokenResponse:
        """撤销令牌。"""
        body = {} if token is None else {"token": token}
        return self.request("/token/revoke", RequestOptions(
            method="POST",
            body=body,
        ))
