from __future__ import annotations

import json
from dataclasses import asdict, dataclass

from .json_types import JSONObject, JSONScalar


INVALID_TOKEN_MARKERS = (
    "invalid token",
    "token invalid",
    "token失效",
    "无效token",
    "登录失效",
    "login token invalid",
    "access token invalid",
)


@dataclass(slots=True)
class QingflowApiError(Exception):
    category: str
    message: str
    backend_code: JSONScalar = None
    request_id: str | None = None
    http_status: int | None = None
    details: JSONObject | None = None

    def to_dict(self) -> JSONObject:
        return asdict(self)

    def as_json(self) -> str:
        return json.dumps(self.to_dict(), ensure_ascii=False)

    def __str__(self) -> str:
        return self.as_json()

    def looks_like_invalid_token(self) -> bool:
        text = self.message.lower()
        return any(marker in text for marker in INVALID_TOKEN_MARKERS)

    @classmethod
    def auth_required(cls, profile: str) -> "QingflowApiError":
        return cls(
            category="auth",
            message=f"Profile '{profile}' is not logged in. Run auth_login first.",
        )

    @classmethod
    def workspace_not_selected(cls, profile: str) -> "QingflowApiError":
        return cls(
            category="workspace",
            message=f"WORKSPACE_NOT_SELECTED: profile '{profile}' has no selected workspace. Run workspace_select first.",
        )

    @classmethod
    def config_error(cls, message: str) -> "QingflowApiError":
        return cls(category="config", message=message)

    @classmethod
    def not_supported(cls, message: str) -> "QingflowApiError":
        return cls(category="not_supported", message=message)


def raise_tool_error(error: QingflowApiError) -> None:
    raise RuntimeError(error.as_json())
