from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
import os
from typing import Mapping


def _parse_bool(value: str | None, default: bool) -> bool:
    if value is None:
        return default
    normalized = value.strip().lower()
    if normalized in {"1", "true", "yes", "y", "on"}:
        return True
    if normalized in {"0", "false", "no", "n", "off"}:
        return False
    return default


def _strip_quotes(value: str) -> str:
    if (
        (value.startswith("\"") and value.endswith("\""))
        or (value.startswith("'") and value.endswith("'"))
    ):
        return value[1:-1]
    return value


def load_env_file(path: Path) -> Mapping[str, str]:
    if not path.exists():
        return {}
    entries: dict[str, str] = {}
    for raw_line in path.read_text(encoding="utf-8").splitlines():
        line = raw_line.strip()
        if not line or line.startswith("#"):
            continue
        if line.startswith("export "):
            line = line[len("export ") :].strip()
        if "=" not in line:
            continue
        key, value = line.split("=", 1)
        entries[key.strip()] = _strip_quotes(value.strip())
    return entries


def apply_env_overrides(entries: Mapping[str, str]) -> None:
    for key, value in entries.items():
        os.environ.setdefault(key, value)


def default_env_path() -> Path:
    return Path(os.getenv("RABBITMQ_ENV_FILE", ".env"))


@dataclass(frozen=True)
class RabbitMQConfig:
    env: str
    host: str
    port: int
    amqp_port: int
    username: str
    password: str
    vhost: str
    scheme: str
    verify_ssl: bool
    timeout: float
    max_connections: int
    max_keepalive_connections: int
    retries: int
    retry_backoff: float
    vhost_cache_ttl: float
    allow_destructive: bool

    @property
    def api_base_url(self) -> str:
        return f"{self.scheme}://{self.host}:{self.port}/api"

    @property
    def amqp_url(self) -> str:
        from urllib.parse import quote

        vhost = quote(self.vhost, safe="")
        return f"amqp://{self.username}:{self.password}@{self.host}:{self.amqp_port}/{vhost}"

    @classmethod
    def from_env(cls, env_file: Path | None = None, env: str | None = None) -> "RabbitMQConfig":
        env_value = env if env is not None else os.getenv("RABBITMQ_ENV")
        env_name = (env_value or "test").strip().lower()
        env_file = env_file or default_env_path()
        apply_env_overrides(load_env_file(env_file))

        prefix = "PROD" if env_name == "prod" else "TEST"

        host = os.getenv("RABBITMQ_HOST") or os.getenv(f"{prefix}_RABBITMQ_HOST")
        port_raw = os.getenv("RABBITMQ_PORT") or os.getenv(f"{prefix}_RABBITMQ_PORT")
        username = os.getenv("RABBITMQ_USER") or os.getenv(f"{prefix}_RABBITMQ_USER")
        password = os.getenv("RABBITMQ_PASSWORD") or os.getenv(
            f"{prefix}_RABBITMQ_PASSWORD"
        )

        if not host or not username or not password:
            raise ValueError("RabbitMQ configuration is incomplete")

        port = int(port_raw) if port_raw else 15672
        amqp_port_raw = os.getenv("RABBITMQ_AMQP_PORT") or os.getenv(
            f"{prefix}_RABBITMQ_AMQP_PORT"
        )
        amqp_port = int(amqp_port_raw) if amqp_port_raw else 5672
        vhost = os.getenv("RABBITMQ_VHOST", "/")
        scheme = os.getenv("RABBITMQ_SCHEME", "http")
        verify_ssl = _parse_bool(os.getenv("RABBITMQ_VERIFY_SSL"), scheme == "https")
        timeout = float(os.getenv("RABBITMQ_TIMEOUT", "10"))
        max_connections = int(os.getenv("RABBITMQ_MAX_CONNECTIONS", "20"))
        max_keepalive = int(os.getenv("RABBITMQ_MAX_KEEPALIVE", "10"))
        retries = int(os.getenv("RABBITMQ_RETRIES", "1"))
        retry_backoff = float(os.getenv("RABBITMQ_RETRY_BACKOFF", "0.2"))
        vhost_cache_ttl = float(os.getenv("RABBITMQ_VHOST_CACHE_TTL", "60"))
        allow_destructive = _parse_bool(os.getenv("RABBITMQ_ALLOW_DESTRUCTIVE"), False)

        return cls(
            env=env_name,
            host=host,
            port=port,
            amqp_port=amqp_port,
            username=username,
            password=password,
            vhost=vhost,
            scheme=scheme,
            verify_ssl=verify_ssl,
            timeout=timeout,
            max_connections=max_connections,
            max_keepalive_connections=max_keepalive,
            retries=retries,
            retry_backoff=retry_backoff,
            vhost_cache_ttl=vhost_cache_ttl,
            allow_destructive=allow_destructive,
        )
