"""Common Configurations for the Gateway Server."""

import asyncio
import os
import threading
from typing import Optional

import fastapi
from httpx import HTTPStatusError

from gateway.common.guardrails import Guardrail, GuardrailAction, GuardrailRuleSet


def extract_policy_from_headers(request: Optional[fastapi.Request]) -> Optional[str]:
    """
    Extracts the guardrailing policy from the request headers if present.

    Returns 'None' if no such header is present.
    """
    if request is None:
        return None

    policy = request.headers.get("Invariant-Guardrails")
    # undo unicode_escape
    if policy:
        # interpret as bytes then decode
        policy = policy.encode("utf-8").decode("unicode_escape")
    return policy


class GatewayConfig:
    """Common configurations for the Gateway Server."""

    def __init__(self):
        self.guardrails_from_file = self._load_guardrails_from_file()

    def _load_guardrails_from_file(self) -> str:
        """
        Loads the guardrails from the file specified in GUARDRAILS_FILE_PATH.
        Returns the guardrails file content as a string.
        """
        from gateway.integrations.guardrails import _preload

        guardrails_file = os.getenv("GUARDRAILS_FILE_PATH", "")
        if not guardrails_file:
            print("[warning: GUARDRAILS_FILE_PATH is not set. Using empty guardrails]")
            return ""

        invariant_api_key = os.getenv("INVARIANT_API_KEY", "")
        if not invariant_api_key:
            raise ValueError(
                "Error: INVARIANT_API_KEY is not set."
                "It is required to validate guardrails file content."
            )

        try:
            with open(guardrails_file, "r", encoding="utf-8") as f:
                guardrails_file_content = f.read()
                asyncio.run(
                    _preload(guardrails_file_content, "Bearer " + invariant_api_key)
                )
                return guardrails_file_content

        except (FileNotFoundError, PermissionError, OSError) as e:
            raise ValueError(
                f"Unable to read guardrails file ({guardrails_file}): {e}"
            ) from e
        except HTTPStatusError as e:
            raise ValueError(f"Cannot load guardrails, {e}, {e.response.text}") from e

    def __repr__(self) -> str:
        return f"GatewayConfig(guardrails_from_file={repr(self.guardrails_from_file)})"


class GatewayConfigManager:
    """Manager for Gateway Configuration."""

    _config_instance = None
    _lock = threading.Lock()

    @classmethod
    def get_config(cls, request: fastapi.Request = None) -> GatewayConfig:
        """Initializes and returns the gateway configuration using double-checked locking."""
        local_config = cls._config_instance

        if local_config is None:
            with cls._lock:
                local_config = cls._config_instance
                if local_config is None:
                    local_config = GatewayConfig()
                    cls._config_instance = local_config

        return local_config


async def extract_guardrails_from_header(
    request: fastapi.Request,
) -> Optional[GuardrailRuleSet]:
    """
    Extracts Invariant-Guardrails from the request header if provided, and returns a corresponding
    GuardrailRuleSet. If no guardrails are provided, returns None.
    """
    # if provided in header, use custom guardrailing policy
    if guardrails := extract_policy_from_headers(request):
        guardrails = [
            Guardrail(
                id="guardrails-from-header",
                name="guardrails from request header",
                content=guardrails,
                action=GuardrailAction.BLOCK,
            )
        ]

        return GuardrailRuleSet(
            blocking_guardrails=guardrails,
            logging_guardrails=[],
        )
