# apps/aroflo_connector_app/core/client.py

from __future__ import annotations

from typing import Dict, Any, Optional, Tuple

from urllib.parse import urlencode
import requests

from .auth import build_authorization_value, build_hmac_signature, build_timestamp
from .config import settings


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

    - Arma la URL y el querystring (VarString).
    - Firma la petición con HMAC usando los helpers de core/auth.py.
    - Hace la petición HTTP y devuelve el JSON.
    """

    def __init__(self, base_url: Optional[str] = None) -> None:
        self.base_url = (base_url or settings.base_url).rstrip("/")

    # -------------------------------------------------------------
    # Utilidades internas
    # -------------------------------------------------------------
    def _build_url_and_qs(self, params: Dict[str, str]) -> Tuple[str, str]:
        """
        Construye la URL base y el querystring (VarString) igual que Postman.
        """
        qs = urlencode(params)
        url = f"{self.base_url}/?{qs}"
        return url, qs

    def _prepare_headers(self, method: str, var_string: str) -> Dict[str, str]:
        """
        Construye los headers HMAC usando los helpers existentes.
        """
        authorization = build_authorization_value()
        iso_timestamp = build_timestamp()
        _sig, headers = build_hmac_signature(
            request_type=method.upper(),
            var_string=var_string,
            authorization=authorization,
            iso_timestamp=iso_timestamp,
        )
        return headers

    # -------------------------------------------------------------
    # Método genérico
    # -------------------------------------------------------------
    def request(
        self,
        *,
        zone: str,
        page: int = 1,
        where: Optional[str] = None,
        order: Optional[str] = None,
        join: Optional[str] = None,
        extra_params: Optional[Dict[str, Any]] = None,
        method: str = "GET",
    ) -> Dict[str, Any]:
        """
        Wrapper genérico para llamar cualquier zona de AroFlo.

        - zone: nombre de la zona (ej. 'lastupdate', 'users', 'timesheets')
        - page: número de página
        - where/order/join: parámetros clásicos de AroFlo
        - extra_params: diccionario de filtros específicos (userid, type, etc.)
        """
        params: Dict[str, str] = {
            "zone": zone,
            "page": str(page),
        }

        if where:
            params["where"] = where
        if order:
            params["order"] = order
        if join:
            params["join"] = join

        if extra_params:
            for k, v in extra_params.items():
                if v is not None:
                    params[k] = str(v)

        url, qs = self._build_url_and_qs(params)
        headers = self._prepare_headers(method, qs)

        resp = requests.request(method.upper(), url, headers=headers, timeout=30)
        resp.raise_for_status()
        return resp.json()

    # -------------------------------------------------------------
    # Azúcar sintáctico opcional (por si quieres seguir usando AroFloZone)
    # -------------------------------------------------------------
    def get_zone(
        self,
        zone: "AroFloZone | str",
        *,
        page: int = 1,
        where: Optional[str] = None,
        order: Optional[str] = None,
        join: Optional[str] = None,
        extra_params: Optional[Dict[str, Any]] = None,
        method: str = "GET",
    ) -> Dict[str, Any]:
        """
        Wrapper sencillito alrededor de request() que acepta AroFloZone.
        """
        try:
            from .domain import AroFloZone
        except ImportError:
            AroFloZone = None  # por si acaso

        if AroFloZone and isinstance(zone, AroFloZone):
            zone_value = zone.value
        else:
            zone_value = str(zone)

        return self.request(
            zone=zone_value,
            page=page,
            where=where,
            order=order,
            join=join,
            extra_params=extra_params,
            method=method,
        )
