"""
Traducción de los fallos de Google a motivos accionables.

Google devuelve códigos HTTP y un mensaje en inglés pensado para quien programa,
no para quien opera un sitio. La diferencia entre «no tenés permiso sobre esta
propiedad» y «esta propiedad no existe en tu Search Console» se resuelve en dos
pantallas distintas, y confundirlas manda a la persona al lugar equivocado.

Por eso la clasificación vive acá y no repartida en cada llamada: es la misma
tabla para todas, y tenerla en un solo lugar permite probarla contra las
respuestas grabadas sin tocar a Google.
"""

from dataclasses import dataclass


class GoogleErrorCode:
    PERMISSION_DENIED = 'PERMISSION_DENIED'
    PROPERTY_NOT_FOUND = 'PROPERTY_NOT_FOUND'
    API_NOT_ENABLED = 'API_NOT_ENABLED'
    INVALID_KEY = 'INVALID_KEY'
    QUOTA_EXCEEDED = 'QUOTA_EXCEEDED'
    RATE_LIMITED = 'RATE_LIMITED'
    PROVIDER_UNAVAILABLE = 'PROVIDER_UNAVAILABLE'
    UNEXPECTED = 'UNEXPECTED'


#: Motivos que no mejoran reintentando. Distinguirlos importa: reintentar un
#: permiso denegado gasta cuota y tiempo para volver al mismo lugar.
PERMANENT_CODES = frozenset(
    {
        GoogleErrorCode.PERMISSION_DENIED,
        GoogleErrorCode.PROPERTY_NOT_FOUND,
        GoogleErrorCode.API_NOT_ENABLED,
        GoogleErrorCode.INVALID_KEY,
    }
)

MESSAGES = {
    GoogleErrorCode.PERMISSION_DENIED: (
        'La cuenta de servicio no tiene permiso sobre esta propiedad. Agregala en Search '
        'Console como propietaria: un permiso menor no habilita la inspección de URLs.'
    ),
    GoogleErrorCode.PROPERTY_NOT_FOUND: (
        'Esa propiedad no existe en la Search Console de esta cuenta de servicio. '
        'Revisá si el sitio está dado de alta como propiedad de dominio o de prefijo.'
    ),
    GoogleErrorCode.API_NOT_ENABLED: (
        'La API de Search Console no está habilitada en el proyecto de Google Cloud. '
        'Habilitala desde APIs y servicios → Biblioteca.'
    ),
    GoogleErrorCode.INVALID_KEY: (
        'Google rechazó la clave. Puede estar vencida, borrada desde la consola o '
        'pertenecer a otro proyecto.'
    ),
    GoogleErrorCode.QUOTA_EXCEEDED: (
        'Google reporta la cuota diaria agotada para esta propiedad. Se retoma mañana.'
    ),
    GoogleErrorCode.RATE_LIMITED: (
        'Google está limitando el ritmo de las consultas. Se reintenta solo, más despacio.'
    ),
    GoogleErrorCode.PROVIDER_UNAVAILABLE: (
        'Google no respondió. No es un problema de tu sitio ni de tu credencial.'
    ),
    GoogleErrorCode.UNEXPECTED: 'Google devolvió una respuesta que no esperábamos.',
}


@dataclass
class GoogleCallError(Exception):
    """Fallo de una llamada a Google, ya clasificado."""

    code: str
    message: str = ''
    http_status: int | None = None
    detail: str = ''

    def __post_init__(self):
        if not self.message:
            self.message = MESSAGES.get(self.code, MESSAGES[GoogleErrorCode.UNEXPECTED])

    def __str__(self) -> str:
        return f'{self.code}: {self.message}'

    @property
    def is_permanent(self) -> bool:
        return self.code in PERMANENT_CODES


def classify(status: int | None, body: str = '') -> str:
    """
    Elige el motivo a partir del estado y del cuerpo de la respuesta.

    El cuerpo hace falta porque Google usa 403 para dos cosas muy distintas: que
    la API no está habilitada en el proyecto y que la cuenta de servicio no
    tiene permiso sobre la propiedad. Mirar sólo el código las mezcla, y son la
    primera y la última pantalla del recorrido de configuración.
    """
    text = (body or '').lower()

    if status == 403:
        if 'has not been used' in text or 'is disabled' in text or 'accessnotconfigured' in text:
            return GoogleErrorCode.API_NOT_ENABLED
        if 'quota' in text or 'rate limit' in text:
            return GoogleErrorCode.QUOTA_EXCEEDED
        return GoogleErrorCode.PERMISSION_DENIED

    if status == 401:
        return GoogleErrorCode.INVALID_KEY
    if status == 404:
        return GoogleErrorCode.PROPERTY_NOT_FOUND
    if status == 429:
        return GoogleErrorCode.QUOTA_EXCEEDED if 'daily' in text else GoogleErrorCode.RATE_LIMITED
    if status is not None and status >= 500:
        return GoogleErrorCode.PROVIDER_UNAVAILABLE

    return GoogleErrorCode.UNEXPECTED
