from __future__ import annotations

import os
from pathlib import Path
from typing import Any

ROOT = Path(__file__).resolve().parent.parent
SRC_DIR = Path(__file__).resolve().parent

_APPLIED = False
_LAST_RESULT: dict[str, Any] = {}

_CONFIG_MAP: dict[str, str] = {
    "app.db_path": "AGENT_APP_DB_PATH",
    "security.data_encryption_key": "AGENT_DATA_ENCRYPTION_KEY",
    "auth.allow_signup": "AGENT_AUTH_ALLOW_SIGNUP",
    "auth.session_expires_hours": "AGENT_AUTH_SESSION_EXPIRES_HOURS",
    "auth.bootstrap_username": "AGENT_AUTH_BOOTSTRAP_USERNAME",
    "auth.bootstrap_password": "AGENT_AUTH_BOOTSTRAP_PASSWORD",
    "auth.bootstrap_role": "AGENT_AUTH_BOOTSTRAP_ROLE",
    "agent.state.enabled": "AGENT_DEEP_STATE_ENABLED",
    "agent.state.required": "AGENT_DEEP_STATE_REQUIRED",
    "agent.state.backend_mode": "AGENT_DEEP_BACKEND_MODE",
    "agent.state.sqlite_path": "AGENT_DEEP_CHECKPOINT_SQLITE_PATH",
    "agent.tool.profile": "AGENT_LANGFUSE_TOOL_PROFILE",
    "agent.tool.preset": "AGENT_LANGFUSE_TOOL_PRESET",
    "agent.tool.enable_control": "AGENT_LANGFUSE_TOOLS_ENABLE_CONTROL",
    "agent.tool.enable_openapi_execute": "AGENT_LANGFUSE_TOOLS_ENABLE_OPENAPI_EXECUTE",
    "agent.tool.enable_mutation": "AGENT_LANGFUSE_TOOLS_ENABLE_MUTATION",
    "agent.local_commands_enabled": "AGENT_LOCAL_COMMANDS_ENABLED",
    "agent.openapi.allowlist": "AGENT_LANGFUSE_OPENAPI_ALLOWLIST",
    "agent.openapi.denylist": "AGENT_LANGFUSE_OPENAPI_DENYLIST",
    "agent.openapi.dynamic_tools": "AGENT_LANGFUSE_OPENAPI_DYNAMIC_TOOLS",
    "agent.openapi.dynamic_include_mutating": "AGENT_LANGFUSE_OPENAPI_DYNAMIC_INCLUDE_MUTATING",
    "agent.openapi.dynamic_tool_max": "AGENT_LANGFUSE_OPENAPI_DYNAMIC_TOOL_MAX",
    "settings.defaults.mode": "AGENT_DEFAULT_MODE",
    "settings.defaults.limit": "AGENT_DEFAULT_LIMIT",
    "settings.defaults.timezone": "AGENT_DEFAULT_TIMEZONE",
    "settings.defaults.retention_days": "AGENT_RETENTION_DAYS",
    "settings.defaults.compare_models": "AGENT_DEFAULT_COMPARE_MODELS",
    "settings.integrations.slack_webhook": "AGENT_SLACK_WEBHOOK",
    "settings.integrations.alert_webhook": "AGENT_ALERT_WEBHOOK",
    "settings.integrations.alert_email_recipients": "AGENT_ALERT_EMAIL_RECIPIENTS",
    "settings.integrations.alerts_enabled": "AGENT_ALERTS_ENABLED",
    "settings.llm.openrouter_base_url": "OPENROUTER_BASE_URL",
}


def _candidate_paths() -> list[Path]:
    explicit = str(os.getenv("AGENT_CONFIG_YAML_PATH", "")).strip()
    candidates: list[Path] = []
    if explicit:
        p = Path(explicit)
        if not p.is_absolute():
            p = ROOT / p
        candidates.append(p)
    candidates.extend(
        [
            ROOT / "Config.yaml",
            SRC_DIR / "config" / "Config.yaml",
            SRC_DIR / "config" / "config.yaml",
        ]
    )

    deduped: list[Path] = []
    seen: set[str] = set()
    for item in candidates:
        key = str(item.resolve()) if item.exists() else str(item)
        if key in seen:
            continue
        seen.add(key)
        deduped.append(item)
    return deduped


def _load_yaml(path: Path) -> dict[str, Any] | None:
    try:
        import yaml  # type: ignore
    except Exception:
        return None
    if not path.exists():
        return None
    try:
        payload = yaml.safe_load(path.read_text(encoding="utf-8"))
    except Exception:
        return None
    if not isinstance(payload, dict):
        return None
    return payload


def _get_nested(payload: dict[str, Any], dotted: str) -> Any:
    current: Any = payload
    for segment in dotted.split("."):
        if not isinstance(current, dict) or segment not in current:
            return None
        current = current[segment]
    return current


def _to_env_string(value: Any) -> str:
    if value is None:
        return ""
    if isinstance(value, bool):
        return "true" if value else "false"
    if isinstance(value, (int, float)):
        return str(value)
    if isinstance(value, list):
        return ",".join(str(item).strip() for item in value if str(item).strip())
    return str(value).strip()


def apply_initial_env_from_config(*, force: bool = False, override_existing: bool = False) -> dict[str, Any]:
    global _APPLIED, _LAST_RESULT
    if _APPLIED and not force:
        return dict(_LAST_RESULT)

    selected_path: Path | None = None
    payload: dict[str, Any] | None = None
    for candidate in _candidate_paths():
        loaded = _load_yaml(candidate)
        if isinstance(loaded, dict):
            selected_path = candidate
            payload = loaded
            break

    if payload is None:
        _LAST_RESULT = {
            "loaded": False,
            "path": None,
            "applied_keys": [],
            "reason": "config yaml not found or unreadable",
        }
        _APPLIED = True
        return dict(_LAST_RESULT)

    applied: list[str] = []
    for source_key, env_key in _CONFIG_MAP.items():
        raw = _get_nested(payload, source_key)
        value = _to_env_string(raw)
        if not value:
            continue
        if not override_existing and str(os.getenv(env_key, "")).strip():
            continue
        os.environ[env_key] = value
        applied.append(env_key)

    _LAST_RESULT = {
        "loaded": True,
        "path": str(selected_path) if selected_path else None,
        "applied_keys": applied,
    }
    _APPLIED = True
    return dict(_LAST_RESULT)


def get_bootstrap_config_status() -> dict[str, Any]:
    return dict(_LAST_RESULT)
