import os
import json
import time
import requests
import pandas as pd
from dataclasses import dataclass

@dataclass
class API:
    """
    Obtiene el url y token de acceso de la API-INVESTMENT-RISK desde la variables de entorno y defince la función de conexión.
    """

    API_URL : str = os.getenv('API_RISK_URL')
    API_TOKEN : str = os.getenv('API_RISK_TOKEN')
    REQUEST_TIMEOUT : int = 120
    MAX_RETRIES : int = 5
    BACKOFF_FACTOR : float = 1.8
    
    def engine(self, url:str=None):
        """
        Función principal para hacer la consulta a la url de la API.

        Args:
            url (str): url de consulta.
        """
        headers = {
            "Authorization": f"Bearer {self.API_TOKEN}"
        }

        retryable_status = {429, 500, 502, 503, 504}
        last_error = None

        for attempt in range(1, self.MAX_RETRIES + 1):
            try:
                response = requests.get(
                    url,
                    headers=headers,
                    stream=True,
                    timeout=self.REQUEST_TIMEOUT,
                )

                if response.status_code == 200:
                    raw = response.raw.read(decode_content=True)
                    data = json.loads(raw)
                    return pd.json_normalize(data)

                message = f"Error de Conexión: {response.status_code} | {response.text}"
                last_error = RuntimeError(message)

                if response.status_code not in retryable_status or attempt == self.MAX_RETRIES:
                    raise last_error

            except requests.RequestException as exc:
                last_error = exc
                if attempt == self.MAX_RETRIES:
                    raise RuntimeError(f"Error de red consultando API: {exc}") from exc

            wait_seconds = self.BACKOFF_FACTOR ** (attempt - 1)
            time.sleep(wait_seconds)

        raise RuntimeError(f"No fue posible consultar la API. Último error: {last_error}")