"""settings.py — единый settings loader LEVBOT (green v2).

Все секреты/коннекторы/инфраструктура — в одном .env. Loader читает .env, типизирует,
валидирует обязательное, поддерживает enabled/disabled коннекторы, fail-fast при отсутствии
обязательных данных, НЕ печатает секреты и НЕ подставляет встроенные/чужие credentials.
Единый объект settings для всего приложения. Логика Green не меняется — меняется только
источник значений (было: разрозненные os.environ.get; стало: этот loader).
"""
import os
import pathlib


class ConfigError(RuntimeError):
    pass


def _load_env_file(path):
    """Минимальный парсер .env (без внешних зависимостей). Реальное окружение имеет приоритет
    (например, когда бот запускается менеджером, передающим переменные напрямую)."""
    p = pathlib.Path(path)
    if not p.is_file():
        return
    for raw in p.read_text(encoding="utf-8").splitlines():
        line = raw.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        k, v = line.split("=", 1)
        k = k.strip()
        v = v.strip().strip('"').strip("'")
        if k and k not in os.environ:
            os.environ[k] = v


def _s(name, default=""):
    return (os.environ.get(name, "") or "").strip() or default


def _b(name, default=False):
    v = _s(name).lower()
    if v == "":
        return default
    return v in ("1", "true", "yes", "on")


def _i(name, default):
    try:
        return int(_s(name) or default)
    except Exception:
        return default


class Settings:
    def __init__(self, env_file=None):
        _load_env_file(env_file or os.environ.get(
            "LEVBOT_ENV_FILE", str(pathlib.Path(__file__).parent / ".env")))
        self.errors = []

        # --- Yandex Cloud / модели (текст обязателен) ---
        self.yandex_api_key = _s("YANDEX_API_KEY")
        self.yandex_folder_id = _s("YANDEX_FOLDER_ID")
        self.yandex_cloud_id = _s("YANDEX_CLOUD_ID")
        self.text_model_id = _s("TEXT_MODEL_ID", "deepseek-v4-flash")
        self.vision_model_id = _s("VISION_MODEL_ID")
        self.yandex_oai_url = _s("YANDEX_OAI_URL", "https://llm.api.cloud.yandex.net/v1/chat/completions")
        self.vision_oai_url = _s("VISION_OAI_URL") or self.yandex_oai_url

        # --- Runtime ---
        self.public_url = _s("PUBLIC_URL")
        self.host = _s("HOST", "127.0.0.1")
        self.port = _i("PORT", 8080)
        self.timezone = _s("TIMEZONE", "Europe/Moscow")
        self.data_dir = _s("DATA_DIR", str(pathlib.Path(__file__).parent))
        self.log_level = _s("LOG_LEVEL", "info").lower()
        self.card_base_url = _s("CARD_BASE_URL", "/cards")

        # --- Совместимые с рантаймом Green значения (те же, что раньше вычислял lev_server) ---
        self.api_key = self.yandex_api_key
        self.folder_id = self.yandex_folder_id
        self.text_model = self.text_model_id
        self.vlm_model = self.vision_model_id
        self.vlm_api_key = self.yandex_api_key           # одна модель-учётка на бота
        self.vlm_folder_id = self.yandex_folder_id
        self.oai_url = self.yandex_oai_url
        self.vlm_oai_url = self.vision_oai_url

        # --- Коннекторы (enabled/disabled; ключи требуются ТОЛЬКО если включён) ---
        self.site_enabled = _b("SITE_ENABLED")
        self.site_public_url = _s("SITE_PUBLIC_URL")
        self.site_webhook_secret = _s("SITE_WEBHOOK_SECRET")
        self.site_chat_per_session_per_minute = _i("SITE_CHAT_PER_SESSION_PER_MINUTE", 10)
        self.site_chat_per_ip_per_minute = _i("SITE_CHAT_PER_IP_PER_MINUTE", 100)
        self.site_chat_trusted_proxies = _s("SITE_CHAT_TRUSTED_PROXIES", "127.0.0.1,::1")
        self.site_chat_global_per_minute = _i("SITE_CHAT_GLOBAL_PER_MINUTE", 120)
        self.site_chat_global_per_hour = _i("SITE_CHAT_GLOBAL_PER_HOUR", 1000)
        self.site_chat_max_concurrent = _i("SITE_CHAT_MAX_CONCURRENT", 4)
        self.site_chat_max_text_chars = _i("SITE_CHAT_MAX_TEXT_CHARS", 12000)
        self.site_chat_max_image_url_chars = _i("SITE_CHAT_MAX_IMAGE_URL_CHARS", 4096)
        self.site_chat_max_body_bytes = _i("SITE_CHAT_MAX_BODY_BYTES", 65536)

        self.telegram_enabled = _b("TELEGRAM_ENABLED")
        self.telegram_bot_token = _s("TELEGRAM_BOT_TOKEN")
        self.telegram_webhook_url = _s("TELEGRAM_WEBHOOK_URL")

        self.avito_enabled = _b("AVITO_ENABLED")
        self.avito_route = _s("AVITO_ROUTE", "direct").strip().lower()
        if self.avito_route == "bitrix24":
            self.avito_route = "bitrix"
        self.avito_client_id = _s("AVITO_CLIENT_ID")
        self.avito_client_secret = _s("AVITO_CLIENT_SECRET")
        self.avito_webhook_secret = _s("AVITO_WEBHOOK_SECRET")

        self.bitrix_enabled = _b("BITRIX_ENABLED")
        self.bitrix_webhook = _s("BITRIX_WEBHOOK_URL").rstrip("/") if self.bitrix_enabled else ""
        self.bitrix_bot_id = _s("BITRIX_BOT_ID") if self.bitrix_enabled else ""
        self.bitrix_client_id = _s("BITRIX_CLIENT_ID") if self.bitrix_enabled else ""
        self.bitrix_client_secret = _s("BITRIX_CLIENT_SECRET") if self.bitrix_enabled else ""
        self.bitrix_event_handler_url = _s("BITRIX_EVENT_HANDLER_URL") if self.bitrix_enabled else ""
        self.bitrix_application_token = self.bitrix_client_secret
        self.bitrix_allow_observe_mode = _b("BITRIX_ALLOW_OBSERVE_MODE", False)
        self.bitrix_token_mode = _s("BITRIX_TOKEN_MODE", "enforce").lower()
        if self.bitrix_token_mode not in {"observe", "capture", "enforce"}:
            self.bitrix_token_mode = "enforce"
        if self.bitrix_token_mode == "observe" and not self.bitrix_allow_observe_mode:
            self.bitrix_token_mode = "enforce"
        self.bitrix_token_capture_phrase = _s("BITRIX_TOKEN_CAPTURE_PHRASE")

        self.amocrm_enabled = _b("AMOCRM_ENABLED")
        self.amocrm_base_url = _s("AMOCRM_BASE_URL")
        self.amocrm_long_lived_token = _s("AMOCRM_LONG_LIVED_TOKEN")
        self.amocrm_account_id = _s("AMOCRM_ACCOUNT_ID")
        self.amocrm_current_user_id = _s("AMOCRM_CURRENT_USER_ID")
        self.amocrm_pipeline_id = _s("AMOCRM_PIPELINE_ID")
        self.amocrm_status_id = _s("AMOCRM_STATUS_ID")
        self.amocrm_tag = _s("AMOCRM_TAG", "LEVBOT")

        # --- Валидация: обязательное + включённый коннектор без ключа = ошибка ---
        if not self.yandex_api_key:
            self.errors.append("YANDEX_API_KEY is required")

        def need(enabled, pairs, label):
            if not enabled:
                return
            for field, val in pairs:
                if not val:
                    self.errors.append("%s enabled but %s is empty" % (label, field))

        need(self.site_enabled, [("SITE_PUBLIC_URL", self.site_public_url)], "Site")
        need(self.telegram_enabled, [("TELEGRAM_BOT_TOKEN", self.telegram_bot_token)], "Telegram")
        if self.avito_enabled:
            if self.avito_route not in {"direct", "bitrix", "amocrm"}:
                self.errors.append("Avito enabled but AVITO_ROUTE is invalid")
            elif self.avito_route == "direct":
                need(True, [("AVITO_CLIENT_ID", self.avito_client_id),
                            ("AVITO_CLIENT_SECRET", self.avito_client_secret)], "Avito")
        need(self.bitrix_enabled, [("BITRIX_WEBHOOK_URL", self.bitrix_webhook)], "Bitrix24")
        need(self.amocrm_enabled, [("AMOCRM_BASE_URL", self.amocrm_base_url),
                                   ("AMOCRM_LONG_LIVED_TOKEN", self.amocrm_long_lived_token),
                                   ("AMOCRM_PIPELINE_ID", self.amocrm_pipeline_id),
                                   ("AMOCRM_STATUS_ID", self.amocrm_status_id)], "amoCRM")

    def validate(self):
        """fail-fast: бросает ConfigError, если чего-то обязательного не хватает."""
        if self.errors:
            raise ConfigError("; ".join(self.errors))
        return True

    def summary(self):
        """Безопасное summary без секретов: только факт наличия/включённости."""
        def has(x):
            return "set" if x else "-"
        return {
            "text_model": self.text_model_id,
            "vision_model": self.vision_model_id or "-",
            "yandex_api_key": has(self.yandex_api_key),
            "yandex_folder_id": has(self.yandex_folder_id),
            "public_url": self.public_url or "-",
            "host": self.host, "port": self.port, "timezone": self.timezone,
            "connectors": {
                "site": self.site_enabled, "telegram": self.telegram_enabled,
                "avito": self.avito_enabled, "bitrix24": self.bitrix_enabled,
                "amocrm": self.amocrm_enabled,
            },
            "config_errors": len(self.errors),
        }


def load(env_file=None):
    return Settings(env_file=env_file)


# Единый объект для всего приложения.
settings = load()
