from __future__ import annotations from enum import StrEnum class KakaoTalkErrorKind(StrEnum): AUTH_FAILED = "auth_failed" RATE_LIMITED = "rate_limited" USER_NOT_FOUND = "user_not_found" USER_BLOCKED = "user_blocked" FRIEND_NOT_FOUND = "friend_not_found" SERVER_ERROR = "server_error" NETWORK_ERROR = "network_error" UNKNOWN = "unknown" KAKAO_ERROR_MAP = { -1: (KakaoTalkErrorKind.SERVER_ERROR, "Internal server error"), -2: (KakaoTalkErrorKind.SERVER_ERROR, "Service temporarily unavailable"), -10: (KakaoTalkErrorKind.AUTH_FAILED, "AppKey not found"), -30: (KakaoTalkErrorKind.AUTH_FAILED, "Invalid parameter"), -31: (KakaoTalkErrorKind.AUTH_FAILED, "Required parameter missing"), -32: (KakaoTalkErrorKind.AUTH_FAILED, "Not supported API version"), -401: (KakaoTalkErrorKind.AUTH_FAILED, "Invalid access token"), -402: (KakaoTalkErrorKind.AUTH_FAILED, "Admin Key expired or revoked"), -403: (KakaoTalkErrorKind.AUTH_FAILED, "Insufficient scope"), -501: (KakaoTalkErrorKind.USER_NOT_FOUND, "User not found"), -502: (KakaoTalkErrorKind.USER_BLOCKED, "User blocked the channel"), -503: (KakaoTalkErrorKind.FRIEND_NOT_FOUND, "User is not a friend"), -601: (KakaoTalkErrorKind.RATE_LIMITED, "Rate limit exceeded"), } def classify_error(status_code: int, response_body: dict | None = None) -> tuple[KakaoTalkErrorKind, str]: if status_code == 401: return KakaoTalkErrorKind.AUTH_FAILED, "Admin Key invalid or expired" if status_code == 429: return KakaoTalkErrorKind.RATE_LIMITED, "Rate limit exceeded" if status_code >= 500: return KakaoTalkErrorKind.SERVER_ERROR, f"Server error {status_code}" if response_body: code = response_body.get("code", 0) if code in KAKAO_ERROR_MAP: return KAKAO_ERROR_MAP[code] return KakaoTalkErrorKind.UNKNOWN, f"Unknown error (HTTP {status_code})"