import logging
import httpx
from json.decoder import JSONDecodeError
import pydantic
from fastapi import HTTPException

from idunn import settings
from .models import QueryParams, ExtraParams

logger = logging.getLogger(__name__)


class BragiClient:
    def __init__(self):
        self.client = httpx.AsyncClient(verify=settings["VERIFY_HTTPS"])

    async def autocomplete(self, query: QueryParams, extra: ExtraParams):
        params = query.bragi_query_dict()
        body = None
        if extra.shape:
            body = extra.dict()
        return await self.raw_autocomplete(params, body)

    async def raw_autocomplete(self, params, body=None):
        url = settings["BRAGI_BASE_URL"] + "/autocomplete"
        if body:
            response = await self.client.post(url, params=params, json=body)
        else:
            response = await self.client.get(url, params=params)

        if response.status_code != httpx.codes.ok:
            try:
                explain = response.json()["long"]
            except (IndexError, JSONDecodeError):
                explain = response.text
            logger.error(
                'Request to Bragi returned with unexpected status %d: "%s"',
                response.status_code,
                explain,
            )
            raise HTTPException(503, "Unexpected geocoder error")

        try:
            return response.json()
        except (JSONDecodeError, pydantic.ValidationError) as e:
            logger.exception("Autocomplete invalid response")
            raise HTTPException(503, "Invalid response from the geocoder")

    async def pois_query_in_bbox(self, query, bbox, limit, lang=None):
        query_params = {"q": query, "lang": lang, "limit": limit, "type[]": "poi"}
        xmin, ymin, xmax, ymax = bbox
        shape = {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [[xmin, ymin], [xmax, ymin], [xmax, ymax], [xmin, ymax], [xmin, ymin]]
                ],
            },
            "properties": {},
        }
        return await self.raw_autocomplete(params=query_params, body={"shape": shape})


bragi_client = BragiClient()