import logging
from typing import Any, Dict, Optional

import requests

from .config import AroFloSettings, AroFloConfigError
from .auth import (
    build_authorization_value,
    build_timestamp,
    build_hmac_signature,
)

log = logging.getLogger(__name__)


class AroFloError(RuntimeError):
    """Error genérico al hablar con la API de AroFlo."""


class AroFloClient:
    """
    Cliente para la API de AroFlo.

    - Carga settings desde .env
    - Construye headers HMAC (igual Postman)
    - Hace request genérico y parsea JSON
    """

    def __init__(
        self,
        settings: Optional[AroFloSettings] = None,
        session: Optional[requests.Session] = None,
    ) -> None:
        self.settings = settings or AroFloSettings.from_env()
        self.session = session or requests.Session()
        self.session.headers.update(
            {
                "User-Agent": "aroflo-connector-app/0.0.1",
            }
        )

    def request(
        self,
        path: str,
        method: str = "GET",
        *,
        params: Optional[Dict[str, Any]] = None,
        json: Any = None,
        var_string: str = "",
        **kwargs: Any,
    ) -> Any:
        """
        Llamada genérica a AroFlo.

        - path: ruta relativa (ej: '', 'api/v5', etc. según AROFLO_BASE_URL)
        - method: 'GET', 'POST', etc.
        - params: querystring (dict) -> se convertirá a ?a=b&c=d
        - json: body JSON
        - var_string: cadena EXACTA que se usa en el HMAC (zone=...&where=...&page=...)
        """
        url = self.settings.base_url.rstrip("/")
        if path:
            url += "/" + path.lstrip("/")

        authorization = build_authorization_value(self.settings)
        iso_ts = build_timestamp()
        _, hmac_headers = build_hmac_signature(
            request_type=method,
            var_string=var_string or "",
            authorization=authorization,
            iso_timestamp=iso_ts,
            settings=self.settings,
        )

        extra_headers = kwargs.pop("headers", {}) or {}
        headers = {**hmac_headers, **extra_headers}

        if json is not None and "Content-Type" not in headers:
            headers["Content-Type"] = "application/json"

        timeout = kwargs.pop("timeout", self.settings.timeout)

        log.debug(
            "AroFlo request %s %s params=%s json=%s var_string=%s",
            method,
            url,
            params,
            json,
            var_string,
        )

        try:
            resp = self.session.request(
                method.upper(),
                url,
                params=params,
                json=json,
                headers=headers,
                timeout=timeout,
                **kwargs,
            )
        except requests.RequestException as exc:
            raise AroFloError(f"Error de red al conectar con AroFlo: {exc}") from exc

        log.debug(
            "AroFlo response status=%s headers=%s",
            resp.status_code,
            dict(resp.headers),
        )

        try:
            data = resp.json()
        except ValueError as exc:
            raise AroFloError(
                f"Respuesta no JSON desde AroFlo (status={resp.status_code}): {resp.text!r}"
            ) from exc

        status = data.get("status")

        if resp.status_code >= 400 or (status not in (None, "0", 0, "OK")):
            raise AroFloError(
                f"Error en respuesta de AroFlo. HTTP={resp.status_code}, payload={data!r}"
            )

        return data
