"""Configuration helpers for the Sandai operator client."""

import os
from dataclasses import dataclass
from typing import Dict, List, Optional

VALID_PRIORITIES = ("high", "normal", "low", "very_low")
_DEFAULT_BROKER_URL = "redis://localhost:6379/0"
_DEFAULT_ACCEPT_CONTENT = ["json", "msgpack"]


def _default_accept_content(task_serializer: str, result_serializer: str) -> List[str]:
    values = list(_DEFAULT_ACCEPT_CONTENT)
    for serializer in (task_serializer, result_serializer):
        if serializer and serializer not in values:
            values.append(serializer)
    return values


def env_bool(name: str, default: bool = False) -> bool:
    value = os.getenv(name)
    if value is None:
        return default
    return value.strip().lower() in {"1", "true", "yes", "on"}


@dataclass
class CeleryConfig:
    """Celery connection settings."""

    broker_url: str
    result_backend: str
    task_serializer: str = "msgpack"
    result_serializer: str = "json"
    accept_content: Optional[List[str]] = None

    def __post_init__(self) -> None:
        if self.accept_content is None:
            self.accept_content = _default_accept_content(
                self.task_serializer,
                self.result_serializer,
            )


@dataclass(frozen=True)
class ClientConfig:
    """Resolved runtime configuration for ``OperatorClient``."""

    operator_name: str
    operator_version: str
    celery: CeleryConfig
    timeout: int = 28800
    debug: bool = False
    priority: str = "normal"
    cancel_key: Optional[str] = None
    auto_forget_result: bool = True

    @property
    def broker_url(self) -> str:
        return self.celery.broker_url

    @property
    def result_backend(self) -> str:
        return self.celery.result_backend

    @property
    def task_name(self) -> str:
        return f"sandai_operator.{self.operator_name}.{self.operator_version}.process_task"

    @property
    def app_name(self) -> str:
        return f"sandai_client_{self.operator_name}_{self.operator_version}"

    @property
    def queue_names(self) -> Dict[str, str]:
        return {
            priority: f"{priority}.{self.operator_name}.{self.operator_version}"
            for priority in VALID_PRIORITIES
        }


def get_celery_config() -> Optional[CeleryConfig]:
    """Read Celery configuration from environment variables."""

    broker_url = os.getenv("SANDAI_OPERATOR_CELERY_BROKER_URL")
    result_backend = os.getenv("SANDAI_OPERATOR_CELERY_RESULT_BACKEND", broker_url)
    task_serializer = os.getenv("SANDAI_OPERATOR_CELERY_TASK_SERIALIZER", "msgpack")
    result_serializer = os.getenv(
        "SANDAI_OPERATOR_CELERY_RESULT_SERIALIZER", "json"
    )

    if not (broker_url and result_backend):
        return None

    return CeleryConfig(
        broker_url=broker_url,
        result_backend=result_backend,
        task_serializer=task_serializer,
        result_serializer=result_serializer,
    )


def get_default_celery_config() -> CeleryConfig:
    """Return the local-development Celery defaults."""

    return CeleryConfig(
        broker_url=_DEFAULT_BROKER_URL,
        result_backend=_DEFAULT_BROKER_URL,
    )


def resolve_client_config(
    operator_name: str,
    operator_version: str,
    *,
    broker_url: Optional[str] = None,
    result_backend: Optional[str] = None,
    timeout: int = 28800,
    debug: bool = False,
    priority: str = "normal",
    cancel_key: Optional[str] = None,
    auto_forget_result: Optional[bool] = None,
) -> ClientConfig:
    """Resolve the effective client configuration without creating transport state."""

    if broker_url or result_backend:
        resolved_broker_url = broker_url or _DEFAULT_BROKER_URL
        resolved_result_backend = result_backend or resolved_broker_url
        celery = CeleryConfig(
            broker_url=resolved_broker_url,
            result_backend=resolved_result_backend,
        )
    else:
        celery = get_celery_config() or get_default_celery_config()

    return ClientConfig(
        operator_name=operator_name,
        operator_version=operator_version,
        celery=celery,
        timeout=timeout,
        debug=debug,
        priority=priority,
        cancel_key=cancel_key,
        auto_forget_result=(
            auto_forget_result
            if auto_forget_result is not None
            else env_bool("SANDAI_OPERATOR_AUTO_FORGET_RESULT", True)
        ),
    )
