"""
Configuration module.

Loads every setting from the `.env` file located next to this file.
No secret is hard-coded; required values are validated by `validate_config()`
which is called at startup (see main.py).
"""

from __future__ import annotations

import logging
import os
from pathlib import Path
from typing import Optional

from dotenv import load_dotenv

logger = logging.getLogger(__name__)

BASE_DIR = Path(__file__).resolve().parent

# Load .env from the project root (this file's directory).
load_dotenv(BASE_DIR / ".env")


def _get_str(key: str, default: str = "") -> str:
    """Read a string environment variable (stripped, empty-safe)."""
    value = os.getenv(key)
    if value is None:
        return default
    return value.strip()


def _get_int(key: str, default: int) -> int:
    """Read an integer environment variable, falling back to `default`."""
    raw = _get_str(key)
    try:
        return int(raw)
    except (TypeError, ValueError):
        if raw:
            logger.warning("Invalid integer for %s (%r), using default %s", key, raw, default)
        return default


def _get_bool(key: str, default: bool) -> bool:
    """Read a boolean environment variable (1/true/yes/on)."""
    raw = _get_str(key).lower()
    if raw in {"1", "true", "yes", "on", "y"}:
        return True
    if raw in {"0", "false", "no", "off", "n"}:
        return False
    return default


def _resolve_path(value: str, default: str) -> Path:
    """Resolve a path from .env; relative paths are anchored at BASE_DIR."""
    path = Path(value) if value else Path(default)
    return path if path.is_absolute() else BASE_DIR / path


# --------------------------------------------------------------------------- #
# Values loaded from environment
# --------------------------------------------------------------------------- #

BOT_TOKEN: str = _get_str("BOT_TOKEN")

_admin_id_raw = _get_str("ADMIN_ID")
try:
    ADMIN_ID: Optional[int] = int(_admin_id_raw) if _admin_id_raw else None
except ValueError:
    ADMIN_ID = None

DATABASE_PATH: Path = _resolve_path(_get_str("DATABASE_PATH"), "data/bot.db")
DOWNLOAD_PATH: Path = _resolve_path(_get_str("DOWNLOAD_PATH"), "downloads")

MAX_FILE_SIZE_MB: int = max(1, _get_int("MAX_FILE_SIZE_MB", 2000))
MAX_CONCURRENT_DOWNLOADS: int = max(1, _get_int("MAX_CONCURRENT_DOWNLOADS", 2))
FORCE_JOIN_ENABLED: bool = _get_bool("FORCE_JOIN_ENABLED", False)

LOG_LEVEL: str = (_get_str("LOG_LEVEL", "INFO") or "INFO").upper()

# Upload limit of the standard (cloud) Telegram Bot API for bots, in MB.
# Files larger than this can never be uploaded by a bot on the cloud API.
TELEGRAM_BOT_UPLOAD_LIMIT_MB: int = 50


def validate_config() -> list[str]:
    """Validate required configuration values.

    Returns a list of human-readable problems. An empty list means the
    configuration is usable.
    """
    problems: list[str] = []

    if not BOT_TOKEN or BOT_TOKEN == "PUT_YOUR_BOT_TOKEN_HERE":
        problems.append(
            "BOT_TOKEN is missing. Put the token you received from @BotFather "
            "into the .env file (BOT_TOKEN=123456:ABC-DEF...)."
        )
    elif ":" not in BOT_TOKEN:
        problems.append(
            "BOT_TOKEN does not look like a valid Telegram bot token "
            "(expected format: 123456:ABC-DEF...)."
        )

    if ADMIN_ID is None:
        problems.append(
            "ADMIN_ID is missing or invalid. Put your numeric Telegram user id "
            "into the .env file (ADMIN_ID=123456789). See README for how to find it."
        )

    if not (1 <= MAX_CONCURRENT_DOWNLOADS <= 50):
        problems.append("MAX_CONCURRENT_DOWNLOADS must be between 1 and 50.")

    return problems
