"""HTTP client for the Synup API."""

from __future__ import annotations

from typing import Any

import requests

from synup.exceptions import SynupAPIError

DEFAULT_BASE_URL = "https://api.synup.com"


class SynupClient:
    """Client for the Synup v4 API."""

    def __init__(self, api_key: str, base_url: str | None = None):
        """
        Initialize the client.

        Args:
            api_key: Your Synup API key.
            base_url: Base URL for the API. Defaults to https://api.synup.com.
        """
        self._api_key = api_key
        self._base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
        self._session = requests.Session()
        self._session.headers.update(
            {
                "Authorization": f"API {self._api_key}",
                "Content-Type": "application/json",
            }
        )

    def fetch_all_locations(
        self,
        first: int | None = None,
        after: str | None = None,
        before: str | None = None,
        last: int | None = None,
        fetch_all: bool = False,
        page_size: int = 100,
    ) -> list[dict[str, Any]] | dict[str, Any]:
        """
        Fetch locations from the account.

        Args:
            first: Number of records to fetch from the beginning.
            after: Cursor to fetch records after (for pagination).
            before: Cursor to fetch records before (for pagination).
            last: Number of records to fetch from the end.
            fetch_all: If True, auto-paginate and return a flat list of all location nodes.
            page_size: When fetch_all is True, number of records per request (default 100).

        Returns:
            If fetch_all is False: a dict with "locations", "page_info", and optionally "raw".
            If fetch_all is True: a list of location node dicts.
        """
        if fetch_all:
            return self._fetch_all_locations_paginated(page_size=page_size)
        return self._fetch_locations_page(first=first, after=after, before=before, last=last)

    def _fetch_locations_page(
        self,
        first: int | None = None,
        after: str | None = None,
        before: str | None = None,
        last: int | None = None,
    ) -> dict[str, Any]:
        """Perform a single GET to /api/v4/locations and return parsed result."""
        params: dict[str, str | int] = {}
        if first is not None:
            params["first"] = first
        if after is not None:
            params["after"] = after
        if before is not None:
            params["before"] = before
        if last is not None:
            params["last"] = last

        url = f"{self._base_url}/api/v4/locations"
        response = self._session.get(url, params=params)

        if not response.ok:
            raise SynupAPIError(
                message=f"API request failed: {response.status_code}",
                status_code=response.status_code,
                response_body=response.text,
            )

        data = response.json()
        all_locations = data.get("data", {}).get("allLocations") or {}
        edges = all_locations.get("edges") or []
        page_info = all_locations.get("pageInfo") or {}

        locations = [edge["node"] for edge in edges]
        start_cursor = edges[0]["cursor"] if edges else None
        end_cursor = edges[-1]["cursor"] if edges else None

        return {
            "locations": locations,
            "page_info": {
                "has_next_page": page_info.get("hasNextPage", False),
                "has_previous_page": page_info.get("hasPreviousPage", False),
                "start_cursor": start_cursor,
                "end_cursor": end_cursor,
            },
            "raw": data,
        }

    def _fetch_all_locations_paginated(self, page_size: int = 100) -> list[dict[str, Any]]:
        """Auto-paginate and return all location nodes."""
        all_nodes: list[dict[str, Any]] = []
        after: str | None = None

        while True:
            page = self._fetch_locations_page(first=page_size, after=after)
            nodes = page["locations"]
            all_nodes.extend(nodes)
            if not page["page_info"]["has_next_page"]:
                break
            after = page["page_info"]["end_cursor"]
            if not after:
                break

        return all_nodes
