from __future__ import annotations

import json
import logging
import os
from dataclasses import dataclass
from pathlib import Path


_DEFAULT_LOCAL_PORT = os.getenv("BRP_LOCAL_BACKEND_PORT", "3000")
_DEFAULT_LOCAL_HOST = os.getenv("BRP_LOCAL_BACKEND_HOST", "localhost")
_LOCAL_BASE = f"http://{_DEFAULT_LOCAL_HOST}:{_DEFAULT_LOCAL_PORT}"


def _load_env_profiles() -> dict[str, dict[str, str]]:
    profiles = {
        "local": {
            "openapi_url": "https://dev-api.lanternbrp.com/api/docs/swagger.json",
            "gateway_base_url": "https://dev-api.lanternbrp.com",
            "auth0_audience": "https://lantern-api/",
        },
        "dev": {
            "openapi_url": "https://dev-api.lanternbrp.com/api/docs/swagger.json",
            "gateway_base_url": "https://dev-api.lanternbrp.com",
            "auth0_audience": "https://lantern-api/",
        },
        "stage": {
            "openapi_url": "https://stage-api.lanternbrp.com/api/docs/swagger.json",
            "gateway_base_url": "https://stage-api.lanternbrp.com",
            "auth0_audience": "https://stage-api.lanternbrp.com/",
        },
        "prod": {
            "openapi_url": "https://api.lanternbrp.com/api/docs/swagger.json",
            "gateway_base_url": "https://api.lanternbrp.com",
            "auth0_audience": "https://api.lanternbrp.com/",
        },
    }
    
    config_path_str = os.getenv("BRP_ENV_CONFIG_PATH", ".config/env_config.json")
    try:
        config_path = Path(config_path_str)
        if config_path.exists():
            with open(config_path, "r", encoding="utf-8") as f:
                custom_profiles = json.load(f)
                for env_name, env_data in custom_profiles.items():
                    # Only merge dicts
                    if isinstance(env_data, dict):
                        if env_name in profiles:
                            profiles[env_name].update(env_data)
                        else:
                            profiles[env_name] = env_data
    except Exception:
        pass
        
    return profiles

ENV_PROFILES = _load_env_profiles()

_LOG_FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"


def configure_logging() -> None:
    """Set up logging for the MCP server.

    When ``BRP_LOG_FILE`` is set the ``brp_mcp`` loggers write directly to
    that file (``propagate=False``) so output isn't duplicated by the
    shell-script redirect (stdout/stderr split by launcher script). Other libraries
    (FastMCP, uvicorn, httpx) still flow through root → stderr → shell
    redirect → the same file.

    When ``BRP_LOG_FILE`` is *not* set everything goes through root's
    ``StreamHandler`` so the shell redirect captures it.
    """
    level = getattr(logging, os.getenv("BRP_LOG_LEVEL", "INFO").upper(), logging.INFO)

    log_file = os.getenv("BRP_LOG_FILE")
    if log_file:
        path = Path(log_file)
        path.parent.mkdir(parents=True, exist_ok=True)
        file_handler = logging.FileHandler(path, mode="a", encoding="utf-8")
        file_handler.setFormatter(logging.Formatter(_LOG_FORMAT))

        brp_logger = logging.getLogger("brp_mcp")
        brp_logger.setLevel(level)
        brp_logger.addHandler(file_handler)
        brp_logger.propagate = False
    else:
        logging.basicConfig(level=level, format=_LOG_FORMAT, force=True)


@dataclass(frozen=True)
class Settings:
    mcp_name: str
    brp_env: str
    openapi_url: str
    openapi_cache_path: Path
    gateway_base_url: str
    auth0_audience: str
    visibility_policy_path: Path
    default_visibility: bool
    used_url_override: bool
    inferred_env: bool
    timeout_seconds: float
    transport: str
    host: str
    port: int


def _infer_env_from_url(value: str | None) -> str | None:
    if not value:
        return None

    lowered = value.lower()
    if "localhost" in lowered or "127.0.0.1" in lowered:
        return "local"
    if "stage-api." in lowered:
        return "stage"
    if "dev-api." in lowered:
        return "dev"
    if "api.lanternbrp.com" in lowered:
        return "prod"
    return None


def _resolve_env(explicit_env: str | None, openapi_url_override: str | None, gateway_url_override: str | None) -> tuple[str, bool]:
    if explicit_env:
        normalized = explicit_env.strip().lower()
        if normalized not in ENV_PROFILES:
            raise ValueError(f"Unsupported BRP_ENV={explicit_env!r}. Expected one of: {', '.join(ENV_PROFILES)}")
        return normalized, False

    inferred = _infer_env_from_url(openapi_url_override) or _infer_env_from_url(gateway_url_override)
    if inferred:
        return inferred, True
    return "dev", True


def load_settings() -> Settings:
    openapi_url_override = os.getenv("BRP_OPENAPI_URL")
    gateway_base_url_override = os.getenv("BRP_GATEWAY_BASE_URL")
    resolved_env, inferred_env = _resolve_env(
        explicit_env=os.getenv("BRP_ENV"),
        openapi_url_override=openapi_url_override,
        gateway_url_override=gateway_base_url_override,
    )
    profile = ENV_PROFILES[resolved_env]

    default_cache_path = f".cache/{resolved_env}-openapi.json"
    return Settings(
        mcp_name=os.getenv("BRP_MCP_NAME", "BRP Gateway MCP"),
        brp_env=resolved_env,
        openapi_url=openapi_url_override or profile["openapi_url"],
        openapi_cache_path=Path(os.getenv("BRP_OPENAPI_CACHE_PATH", default_cache_path)),
        gateway_base_url=gateway_base_url_override or profile["gateway_base_url"],
        auth0_audience=profile["auth0_audience"],
        visibility_policy_path=Path(os.getenv("BRP_VISIBILITY_POLICY_PATH", ".config/mcp_visibility_policy.json")),
        default_visibility=os.getenv("BRP_DEFAULT_VISIBILITY", "false").strip().lower() == "true",
        used_url_override=bool(openapi_url_override or gateway_base_url_override),
        inferred_env=inferred_env,
        timeout_seconds=float(os.getenv("BRP_HTTP_TIMEOUT_SECONDS", "30")),
        transport=os.getenv("BRP_TRANSPORT", "stdio"),
        host=os.getenv("BRP_HOST", "0.0.0.0"),
        port=int(os.getenv("BRP_PORT", "6010")),
    )
