from __future__ import annotations

import os
from dataclasses import dataclass
from pathlib import Path

from dotenv import dotenv_values


SHARED_LARAVEL_ENV_KEYS = {
    "APP_ENV",
    "APP_DEBUG",
    "APP_URL",
    "TELEGRAM_BOT_TOKEN",
    "TELEGRAM_BOT_USERNAME",
    "TELEGRAM_BOT_WEBHOOK_SECRET",
    "BOT_API_TOKEN",
    "DEEPSEEK_API_KEY",
    "DEEPSEEK_BASE_URL",
    "DEEPSEEK_MODEL",
    "GPOS_BASE_URL",
    "GPOS_USERNAME",
    "GPOS_PASSWORD",
    "GPOS_LOGIN_PATH",
    "GPOS_ITEM_DATATABLE_PATH",
    "GPOS_TIMEOUT_SECONDS",
    "GPOS_VERIFY_SSL",
    "GPOS_SALES_BASE_URL",
    "GPOS_SALES_REPORT_PATH",
    "GPOS_PURCHASE_REPORT_PATH",
}

LARAVEL_TO_BOT_ENV_ALIASES = {
    "TELEGRAM_BOT_WEBHOOK_SECRET": "TELEGRAM_WEBHOOK_SECRET",
    "BOT_API_TOKEN": "LARAVEL_API_TOKEN",
    "GPOS_ITEM_DATATABLE_PATH": "GPOS_STOCK_PATH",
    "APP_URL": "LARAVEL_API_BASE_URL",
}


def _load_shared_env() -> None:
    current_dir = Path(__file__).resolve().parent
    bot_dir = current_dir.parent
    project_root = bot_dir.parent

    laravel_env_path = project_root / ".env"
    bot_env_path = bot_dir / ".env"

    if laravel_env_path.is_file():
        laravel_values = dotenv_values(laravel_env_path)

        for source_key, target_key in LARAVEL_TO_BOT_ENV_ALIASES.items():
            value = laravel_values.get(source_key)
            if value is not None and str(value).strip() != "":
                os.environ.setdefault(target_key, str(value).strip())

        for key in SHARED_LARAVEL_ENV_KEYS:
            value = laravel_values.get(key)
            if value is not None and str(value).strip() != "":
                os.environ.setdefault(key, str(value).strip())

    if bot_env_path.is_file():
        bot_values = dotenv_values(bot_env_path)
        for key, value in bot_values.items():
            if value is None:
                continue

            cleaned = str(value).strip()
            if cleaned == "":
                # Nilai kosong di bot/.env tidak boleh menghapus shared config
                # dari ../.env Laravel.
                continue

            os.environ[key] = cleaned


def _env_bool(name: str, default: bool) -> bool:
    value = os.getenv(name)
    if value is None:
        return default

    return value.strip().lower() in {"1", "true", "yes", "on"}


def _env_int(name: str, default: int) -> int:
    value = os.getenv(name)
    if value is None or value.strip() == "":
        return default

    return int(value)


def _env_first(*names: str, default: str = "") -> str:
    for name in names:
        value = os.getenv(name)
        if value is not None and value.strip() != "":
            return value.strip()

    return default


def _env_chat_ids(name: str) -> set[int]:
    raw = os.getenv(name, "").strip()
    if not raw:
        return set()

    values: set[int] = set()
    for part in raw.split(","):
        part = part.strip()
        if not part:
            continue
        values.add(int(part))

    return values


@dataclass(slots=True)
class BotConfig:
    app_env: str
    app_debug: bool
    app_host: str
    app_port: int
    telegram_bot_token: str
    telegram_webhook_secret: str
    telegram_allowed_chat_ids: set[int]
    telegram_timeout_seconds: int
    deepseek_api_key: str
    deepseek_base_url: str
    deepseek_model: str
    deepseek_timeout_seconds: int
    laravel_api_base_url: str
    laravel_api_token: str
    laravel_timeout_seconds: int
    laravel_verify_ssl: bool
    bot_name: str
    bot_enable_invoice_analysis: bool
    bot_enable_laravel_write: bool
    bot_log_level: str
    bot_state_db: str
    # Tesseract OCR — untuk analisis foto faktur
    tesseract_bin: str
    tessdata_dir: str
    tesseract_lang: str
    # GPOS — REST API
    gpos_base_url: str
    gpos_username: str
    gpos_password: str
    gpos_login_path: str
    gpos_stock_path: str
    gpos_timeout_seconds: int
    gpos_sales_base_url: str
    gpos_sales_report_path: str
    gpos_purchase_report_path: str
    # Chat AI — DeepSeek conversational
    bot_enable_chat: bool
    chat_max_history: int

    @classmethod
    def from_env(cls) -> "BotConfig":
        _load_shared_env()

        return cls(
            app_env=os.getenv("APP_ENV", "local"),
            app_debug=_env_bool("APP_DEBUG", True),
            app_host=os.getenv("APP_HOST", "0.0.0.0"),
            app_port=_env_int("APP_PORT", 8080),
            telegram_bot_token=os.getenv("TELEGRAM_BOT_TOKEN", "").strip(),
            telegram_webhook_secret=os.getenv("TELEGRAM_WEBHOOK_SECRET", "").strip(),
            telegram_allowed_chat_ids=_env_chat_ids("TELEGRAM_ALLOWED_CHAT_IDS"),
            telegram_timeout_seconds=_env_int("TELEGRAM_TIMEOUT_SECONDS", 30),
            deepseek_api_key=os.getenv("DEEPSEEK_API_KEY", "").strip(),
            deepseek_base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com").rstrip("/"),
            deepseek_model=os.getenv("DEEPSEEK_MODEL", "deepseek-chat").strip(),
            deepseek_timeout_seconds=_env_int("DEEPSEEK_TIMEOUT_SECONDS", 90),
            laravel_api_base_url=os.getenv("LARAVEL_API_BASE_URL", "").rstrip("/"),
            laravel_api_token=os.getenv("LARAVEL_API_TOKEN", "").strip(),
            laravel_timeout_seconds=_env_int("LARAVEL_TIMEOUT_SECONDS", 30),
            laravel_verify_ssl=_env_bool("LARAVEL_VERIFY_SSL", True),
            bot_name=os.getenv("BOT_NAME", "Bot Delta Waras").strip(),
            bot_enable_invoice_analysis=_env_bool("BOT_ENABLE_INVOICE_ANALYSIS", True),
            bot_enable_laravel_write=_env_bool("BOT_ENABLE_LARAVEL_WRITE", False),
            bot_log_level=os.getenv("BOT_LOG_LEVEL", "INFO").strip(),
            bot_state_db=os.path.expanduser(
                os.getenv("BOT_STATE_DB", "~/bot_state.sqlite3")
            ),
            # Tesseract
            tesseract_bin=os.path.expanduser(
                os.getenv("TESSERACT_BIN", "~/tesseract_local/tesseract")
            ),
            tessdata_dir=os.path.expanduser(
                os.getenv("TESSDATA_DIR", "~/tesseract_local/tessdata")
            ),
            tesseract_lang=os.getenv("TESSERACT_LANG", "ind+eng").strip(),
            # GPOS
            gpos_base_url=os.getenv("GPOS_BASE_URL", "https://mini4.gpos.id").rstrip("/"),
            gpos_username=os.getenv("GPOS_USERNAME", "").strip(),
            gpos_password=os.getenv("GPOS_PASSWORD", "").strip(),
            gpos_login_path=os.getenv("GPOS_LOGIN_PATH", "/api/v1/login").strip(),
            gpos_stock_path=_env_first(
                "GPOS_STOCK_PATH",
                "GPOS_ITEM_DATATABLE_PATH",
                default="/api/v1/item/datatable",
            ),
            gpos_timeout_seconds=_env_int("GPOS_TIMEOUT_SECONDS", 30),
            gpos_sales_base_url=os.getenv("GPOS_SALES_BASE_URL", "https://account.gpos.id").rstrip("/"),
            gpos_sales_report_path=os.getenv("GPOS_SALES_REPORT_PATH", "/api/sales/sales-invoice/list").strip(),
            gpos_purchase_report_path=os.getenv("GPOS_PURCHASE_REPORT_PATH", "/api/purchase/purchase-invoice/list").strip(),
            # Chat AI
            bot_enable_chat=_env_bool("BOT_ENABLE_CHAT", True),
            chat_max_history=_env_int("CHAT_MAX_HISTORY", 10),
        )
