from __future__ import annotations

import logging
import os
from pathlib import Path
from decimal import Decimal, InvalidOperation
from typing import Optional

from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


def _load_dotenv_file(
    path: str | Path = ".env",
) -> None:
    """
    Minimal .env loader using only the Python standard library.

    Existing OS environment variables always win.
    Secrets are never logged.
    """
    env_path = Path(path)

    if not env_path.is_file():
        return

    try:
        lines = env_path.read_text(
            encoding="utf-8",
        ).splitlines()

    except Exception:
        return

    for raw_line in lines:
        line = raw_line.strip()

        if (
            not line
            or line.startswith("#")
            or "=" not in line
        ):
            continue

        key, value = line.split(
            "=",
            1,
        )

        key = key.strip()
        value = value.strip()

        if not key:
            continue

        if (
            len(value) >= 2
            and value[0] == value[-1]
            and value[0] in {"'", '"'}
        ):
            value = value[1:-1]

        os.environ.setdefault(
            key,
            value,
        )


_load_dotenv_file()


logger = logging.getLogger(__name__)


class Settings(BaseSettings):
    """
    تنظیمات اصلی ربات.

    Secrets are loaded from OS environment or project .env.
    Do not hardcode BOT_TOKEN or other secrets here.
    """

    # ============================================================
    # Telegram Bot
    # ============================================================

    BOT_TOKEN: str = Field(
        default="8877295456:AAEnXq3Tv6RBUmV-2j7XrnGQXOUriGyciys",
        description="Telegram Bot Token",
    )

    ADMIN_IDS: str = Field(
        default="8361002510",
        description="Comma-separated Telegram admin IDs",
    )

    # ============================================================
    # Database
    # ============================================================

    DB_PATH: str = "matrix_bot.db"

    # ============================================================
    # MarketApp
    # ============================================================

    MARKET_APP_BASE_URL: str = (
        "https://api.marketapp.org/v1"
    )

    MARKET_APP_TOKEN: str = ""

    MARKET_APP_TIMEOUT: float = 30.0
    MARKET_APP_CONNECT_TIMEOUT: float = 10.0

    MARKET_APP_MAX_CONNECTIONS: int = 100
    MARKET_APP_RETRIES: int = 3

    MARKET_APP_RETRY_DELAY: float = 1.5
    MARKET_APP_MAX_RETRY_DELAY: float = 15.0

    MARKET_APP_RATE_LIMIT_CALLS: int = 10
    MARKET_APP_RATE_LIMIT_PERIOD: float = 1.0

    MARKET_APP_PROXY: Optional[str] = None
    MARKET_APP_VERIFY_SSL: bool = True

    MARKET_APP_USER_AGENT: str = (
        "MatrixBot/MarketAppClient/6.0"
    )

    # ============================================================
    # TON / USDT
    # ============================================================

    TON_USDT_RATE_URL: str = (
        "https://api.binance.com/api/v3/ticker/price"
    )

    TON_USDT_CACHE_TTL: int = 5

    USDT_DECIMALS: int = 8

    MIN_USDT_PRICE: Decimal = Decimal(
        "0.00000001"
    )

    # ============================================================
    # Pricing
    # ============================================================

    PRICING_MARKUP_PERCENT: Decimal = Decimal("10")

    MIN_ORDER_PRICE_TOMAN: int = 1000

    PRICE_ROUND_TO_TOMAN: int = 1000

    # ============================================================
    # Stars
    # ============================================================

    MIN_STARS: int = 50
    MAX_STARS: int = 10_000

    # ============================================================
    # Premium
    # ============================================================

    PREMIUM_MONTHS: tuple[int, ...] = (
        1,
        3,
        6,
        12,
    )

    # ============================================================
    # TON API
    # ============================================================

    TON_API_BASE_URL: str = (
        "https://toncenter.com/api/v2"
    )

    TON_API_KEY: Optional[str] = None

    MERCHANT_WALLET_ADDRESS: str = ""

    # ============================================================
    # Fragment
    # ============================================================

    FRAGMENT_API_BASE_URL: str = (
        "https://fragment.com/api"
    )

    # ============================================================
    # Runtime
    # ============================================================

    DEBUG_MODE: bool = False

    RATE_LIMIT_DEFAULT: float = 1.0

    # ============================================================
    # Application
    # ============================================================

    SUPPORT_USERNAME: str = "@Support_Admin"

    # ============================================================
    # Settings
    # ============================================================

    model_config = SettingsConfigDict(
        extra="ignore",
        case_sensitive=True,
    )

    # ============================================================
    # Validators
    # ============================================================

    @field_validator(
        "MARKET_APP_TIMEOUT",
        "MARKET_APP_CONNECT_TIMEOUT",
        "MARKET_APP_RETRY_DELAY",
        "MARKET_APP_MAX_RETRY_DELAY",
        "MARKET_APP_RATE_LIMIT_PERIOD",
        "RATE_LIMIT_DEFAULT",
    )
    @classmethod
    def validate_positive_float(cls, value):
        if float(value) <= 0:
            raise ValueError(
                "Value must be greater than zero."
            )

        return value

    # ============================================================

    @field_validator(
        "MARKET_APP_MAX_CONNECTIONS",
        "MARKET_APP_RETRIES",
        "MARKET_APP_RATE_LIMIT_CALLS",
        "MIN_STARS",
        "MAX_STARS",
    )
    @classmethod
    def validate_positive_int(cls, value):
        if int(value) <= 0:
            raise ValueError(
                "Value must be greater than zero."
            )

        return value

    # ============================================================

    @field_validator("USDT_DECIMALS")
    @classmethod
    def validate_usdt_decimals(cls, value):
        if not 0 <= int(value) <= 18:
            raise ValueError(
                "USDT_DECIMALS must be between 0 and 18."
            )

        return value

    # ============================================================

    @field_validator("PRICE_ROUND_TO_TOMAN")
    @classmethod
    def validate_price_round(cls, value):
        if int(value) < 0:
            raise ValueError(
                "PRICE_ROUND_TO_TOMAN cannot be negative."
            )

        return value

    # ============================================================

    @field_validator(
        "PRICING_MARKUP_PERCENT",
        mode="before",
    )
    @classmethod
    def validate_markup(cls, value):
        try:
            value = Decimal(str(value))

        except (
            InvalidOperation,
            ValueError,
            TypeError,
        ) as exc:

            raise ValueError(
                "Invalid PRICING_MARKUP_PERCENT."
            ) from exc

        if value < 0:
            raise ValueError(
                "PRICING_MARKUP_PERCENT cannot be negative."
            )

        return value

    # ============================================================
    # Admin IDs
    # ============================================================

    def get_admin_list(self) -> list[int]:
        if not self.ADMIN_IDS:
            return []

        result: list[int] = []

        for raw_id in self.ADMIN_IDS.split(","):

            raw_id = raw_id.strip()

            if not raw_id:
                continue

            try:
                result.append(int(raw_id))

            except ValueError:

                logger.warning(
                    "Invalid admin ID ignored: %s",
                    raw_id,
                )

        return result

    # ============================================================
    # Helpers
    # ============================================================

    def get_usdt_quantize(self) -> Decimal:
        return Decimal(
            "1."
            + (
                "0" * self.USDT_DECIMALS
            )
        )

    # ============================================================
    # Runtime validation
    # ============================================================

    def validate_runtime(self) -> None:

        if (
            not self.BOT_TOKEN.strip()
            or self.BOT_TOKEN
            == "PASTE_YOUR_NEW_BOT_TOKEN_HERE"
        ):

            raise RuntimeError(
                "BOT_TOKEN is not configured. "
                "Set it in .env or the OS environment."
            )

        if ":" not in self.BOT_TOKEN:

            raise RuntimeError(
                "BOT_TOKEN format appears to be invalid."
            )

        if self.MIN_STARS > self.MAX_STARS:

            raise RuntimeError(
                "MIN_STARS cannot be greater than MAX_STARS."
            )

        if self.PRICE_ROUND_TO_TOMAN < 0:

            raise RuntimeError(
                "PRICE_ROUND_TO_TOMAN cannot be negative."
            )


# ================================================================
# Global Settings
# ================================================================

settings = Settings()

settings.validate_runtime()

logger.info(
    "Matrix configuration loaded successfully."
)