"""Guardrail model for applying content guardrails via the Beacon API."""

from __future__ import annotations

import json
import logging
from typing import Any

import httpx

from lumenova_beacon.exceptions import (
    GuardrailError,
    GuardrailNotFoundError,
    GuardrailValidationError,
)
from lumenova_beacon.utils.client_helpers import get_base_url, get_transport
from lumenova_beacon.utils.http_errors import HTTPErrorHandler

logger = logging.getLogger(__name__)

_error_handler = HTTPErrorHandler(
    not_found_exc=GuardrailNotFoundError,
    validation_exc=GuardrailValidationError,
    base_exc=GuardrailError,
)

DEFAULT_CACHE = {
    'ttl': 300,
    's-maxage': 600,
    'no-cache': False,
    'no-store': False,
}


class Guardrail:
    """Apply content guardrails via the Beacon API.

    Provides both sync and async methods for validating text against
    a configured guardrail.

    Args:
        guardrail_id: UUID of the guardrail to apply.

    Examples:
        Sync usage:
            >>> from lumenova_beacon.guardrails import Guardrail
            >>> guardrail = Guardrail('00000000-0000-0000-0000-000000000007')
            >>> result = guardrail.apply('some user input')

        Async usage:
            >>> result = await guardrail.aapply('some user input')
    """

    def __init__(self, guardrail_id: str):
        self.guardrail_id = guardrail_id

    def _build_url(self) -> str:
        base_url = get_base_url()
        return f'{base_url}/api/v1/guardrail/{self.guardrail_id}/apply'

    def _build_payload(self, text: str, cache: dict[str, Any] | None = None) -> dict[str, Any]:
        return {
            'content': [
                {
                    'text': text
                }
            ],
            'cache': cache or DEFAULT_CACHE,
        }

    def apply(self, text: str, cache: dict[str, Any] | None = None) -> dict[str, Any]:
        """Apply guardrail to text (sync).

        Args:
            text: The text to validate.
            cache: Optional cache settings. Uses default TTL settings if not provided.

        Returns:
            The full API response dictionary.

        Raises:
            GuardrailError: If the API call fails.
            GuardrailNotFoundError: If the guardrail ID is not found.
            GuardrailValidationError: If the request is invalid.
        """
        url = self._build_url()
        transport = get_transport('Guardrail operations')
        payload = self._build_payload(text, cache)

        try:
            response = httpx.post(
                url,
                json=payload,
                headers=transport.headers,
                timeout=transport.timeout,
                verify=transport.verify,
            )
            response.raise_for_status()
            return response.json()
        except httpx.HTTPStatusError as e:
            _error_handler.handle(e)
        except httpx.RequestError as e:
            raise GuardrailError(f'Failed to connect to Beacon Guardrails API: {e}') from e
        except json.JSONDecodeError as e:
            raise GuardrailError(f'Invalid response from Beacon Guardrails API: {e}') from e

    async def aapply(self, text: str, cache: dict[str, Any] | None = None) -> dict[str, Any]:
        """Apply guardrail to text (async).

        Args:
            text: The text to validate.
            cache: Optional cache settings. Uses default TTL settings if not provided.

        Returns:
            The full API response dictionary.

        Raises:
            GuardrailError: If the API call fails.
            GuardrailNotFoundError: If the guardrail ID is not found.
            GuardrailValidationError: If the request is invalid.
        """
        url = self._build_url()
        transport = get_transport('Guardrail operations')
        payload = self._build_payload(text, cache)

        try:
            async with httpx.AsyncClient(
                timeout=transport.timeout, verify=transport.verify
            ) as client:
                response = await client.post(
                    url,
                    json=payload,
                    headers=transport.headers,
                )
                response.raise_for_status()
                return response.json()
        except httpx.HTTPStatusError as e:
            _error_handler.handle(e)
        except httpx.RequestError as e:
            raise GuardrailError(f'Failed to connect to Beacon Guardrails API: {e}') from e
        except json.JSONDecodeError as e:
            raise GuardrailError(f'Invalid response from Beacon Guardrails API: {e}') from e
