from __future__ import annotations

import asyncio
import time
from typing import Any

import httpx

from fastcheck_api.app.core.config import settings


class SheriffV2NativeService:
    def __init__(self) -> None:
        self._client = httpx.AsyncClient(timeout=60)
        self._token: str | None = None
        self._token_expires_at: float = 0.0

    async def close(self) -> None:
        await self._client.aclose()

    def _base_url(self) -> str:
        base_url = (settings.sheriff_v2_base_url or "").strip()
        if not base_url:
            raise RuntimeError("Missing BASE_URL")
        return base_url.rstrip("/")

    def _client_identifier(self) -> str:
        return (settings.sheriff_v2_client_identifier or "SheriffSecureClient-v1").strip()

    def _credentials(self) -> tuple[str, str]:
        access_key = (settings.sheriff_v2_access_key or "").strip()
        access_secret = (settings.sheriff_v2_access_secret or "").strip()
        if not access_key or not access_secret:
            raise RuntimeError("Missing shf V2 access credentials")
        return access_key, access_secret

    async def _get_token(self) -> str:
        now = time.time()
        if self._token and now < (self._token_expires_at - 30):
            return self._token

        base_url = self._base_url()
        access_key, access_secret = self._credentials()
        url = f"{base_url}/api/clients/v2/apiCredentials/getToken"
        headers = {
            "Content-Type": "application/json",
            "accept": "application/json",
            "x-client-identifier": self._client_identifier(),
        }
        resp = await self._client.post(url, headers=headers, json={"accessKey": access_key, "accessSecret": access_secret})
        resp.raise_for_status()
        payload = resp.json()
        token: str | None = None
        if isinstance(payload, dict):
            raw = payload.get("data") or payload.get("token") or payload.get("access_token") or payload.get("accessToken")
            if isinstance(raw, str):
                token = raw
            elif isinstance(raw, dict):
                inner = raw.get("token") or raw.get("access_token") or raw.get("accessToken")
                if isinstance(inner, str):
                    token = inner
        token = (token or "").strip()
        if not token:
            raise RuntimeError("shf token response invalid")

        ttl = int(settings.sheriff_v2_token_ttl_seconds or 600)
        self._token = token
        self._token_expires_at = now + ttl
        return token

    async def _request(self, method: str, path: str, *, params: dict[str, Any] | None = None, json: dict[str, Any] | None = None) -> dict[str, Any]:
        base_url = self._base_url()
        url = f"{base_url}{path}"
        token = await self._get_token()
        headers = {
            "accept": "application/json",
            "Authorization": f"Bearer {token}",
            "x-client-identifier": self._client_identifier(),
        }
        resp = await self._client.request(method, url, headers=headers, params=params, json=json)
        if resp.status_code == 401:
            self._token = None
            token = await self._get_token()
            headers["Authorization"] = f"Bearer {token}"
            resp = await self._client.request(method, url, headers=headers, params=params, json=json)
        if resp.status_code >= 400:
            body = (resp.text or "")[:2000]
            raise RuntimeError(f"shf {resp.status_code} for {method} {path}: {body}")
        data = resp.json()
        if not isinstance(data, dict):
            raise RuntimeError("Unexpected shf response")
        return data

    async def query_rut(self, *, rut: str, is_monitoring: bool = False) -> dict[str, Any]:
        rut = (rut or "").strip()
        if not rut:
            raise ValueError("Missing rut")

        cargar = await self._request(
            "POST",
            "/api/clients/v2/helper/cargarRut",
            json={"rut": rut, "isMonitoring": bool(is_monitoring), "includeEquifax": False},
        )
        await asyncio.sleep(2)

        resumen = await self._request(
            "GET",
            "/api/clients/v2/helper/resumen",
            params={"rut": rut, "complete": "True"},
        )

        result: dict[str, Any] = {"success": True, "cargarRut": cargar, "resumen": resumen}

        ok = True
        if isinstance(cargar, dict) and ("success" in cargar) and (not bool(cargar.get("success"))):
            ok = False
        if isinstance(resumen, dict) and ("success" in resumen) and (not bool(resumen.get("success"))):
            ok = False

        if ok:
            judicial_civil, judicial_cobranza, judicial_laboral, multa_laboral, mora_previsional, compliance, malla_societaria, credit_score = await asyncio.gather(
                self._request("GET", f"/api/clients/v2/helper/judicial/{rut}/civil"),
                self._request("GET", f"/api/clients/v2/helper/judicial/{rut}/cobranza"),
                self._request("GET", f"/api/clients/v2/helper/judicial/{rut}/laboral"),
                self._request("GET", f"/api/clients/v2/helper/cobranzaLaboral/{rut}/multaLaboral"),
                self._request("GET", f"/api/clients/v2/helper/cobranzaLaboral/{rut}/moraPrevisional"),
                self._request("GET", f"/api/clients/v2/helper/compliance/{rut}"),
                self._request("GET", f"/api/clients/v2/helper/legal/{rut}/mallaSocietaria"),
                self._request("GET", f"/api/clients/v2/creditScore/{rut}"),
            )
            result.update(
                {
                    "judicial": {"civil": judicial_civil, "cobranza": judicial_cobranza, "laboral": judicial_laboral},
                    "cobranzaLaboral": {"multaLaboral": multa_laboral, "moraPrevisional": mora_previsional},
                    "compliance": compliance,
                    "legal": {"mallaSocietaria": malla_societaria},
                    "creditScore": credit_score,
                }
            )

        return result


sheriff_v2_native_service = SheriffV2NativeService()
