import os
from typing import Any

import httpx
from dotenv import load_dotenv


class AbuseIPDBError(Exception):
    def __init__(self, message: str, status_code: int | None = None):
        self.message = message
        self.status_code = status_code
        super().__init__(self.message)


class AbuseIPDBClient:
    BASE_URL = "https://api.abuseipdb.com/api/v2"

    def __init__(self, api_key: str | None = None):
        if api_key is None and not os.getenv("ABUSEIPDB_TOKEN"):
            load_dotenv()

        self.api_key = api_key or os.getenv("ABUSEIPDB_TOKEN")
        if not self.api_key:
            raise ValueError(
                "API key not found. Set ABUSEIPDB_TOKEN in your environment or a local .env file."
            )
        self._client = httpx.Client(
            headers={
                "Key": self.api_key,
                "Accept": "application/json",
            },
            timeout=30.0,
        )

    def _request(self, method: str, endpoint: str, **kwargs) -> dict[str, Any]:
        url = f"{self.BASE_URL}{endpoint}"
        response = self._client.request(method, url, **kwargs)

        if response.status_code == 429:
            raise AbuseIPDBError("Rate limit exceeded", 429)
        if response.status_code >= 400:
            try:
                error_data = response.json()
                detail = error_data.get("errors", [{}])[0].get("detail", response.text)
            except Exception:
                detail = response.text
            raise AbuseIPDBError(detail, response.status_code)

        return response.json()

    def check_ip(
        self, ip_address: str, max_age_days: int = 30, verbose: bool = False
    ) -> dict[str, Any]:
        params = {
            "ipAddress": ip_address,
            "maxAgeInDays": max_age_days,
        }
        if verbose:
            params["verbose"] = ""
        return self._request("GET", "/check", params=params)

    def check_block(self, network: str, max_age_days: int = 30) -> dict[str, Any]:
        params = {
            "network": network,
            "maxAgeInDays": max_age_days,
        }
        return self._request("GET", "/check-block", params=params)

    def report_ip(
        self,
        ip_address: str,
        categories: str,
        comment: str,
        timestamp: str | None = None,
    ) -> dict[str, Any]:
        data = {
            "ip": ip_address,
            "categories": categories,
            "comment": comment,
        }
        if timestamp:
            data["timestamp"] = timestamp
        return self._request("POST", "/report", data=data)

    def blacklist(
        self,
        confidence_minimum: int = 25,
        limit: int = 10000,
        ip_version: int | None = None,
        only_countries: str | None = None,
    ) -> dict[str, Any]:
        params: dict[str, int | str] = {
            "confidenceMinimum": confidence_minimum,
            "limit": limit,
        }
        if ip_version:
            params["ipVersion"] = ip_version
        if only_countries:
            params["onlyCountries"] = only_countries
        return self._request("GET", "/blacklist", params=params)

    def close(self):
        self._client.close()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
