"""
config.py — конфигурация TelePush.
"""
import os
import sys
from pathlib import Path

# ── Пути ─────────────────────────────────────────────────────────────────────
if getattr(sys, 'frozen', False):
    BASE_DIR = Path(sys.executable).parent
else:
    BASE_DIR = Path(__file__).parent

# ── Версия ───────────────────────────────────────────────────────────────────
# .version файл обновляется при update и лежит рядом с exe
_VERSION_HARDCODE = "1.5.97"
TELEPUSH_VERSION = _VERSION_HARDCODE
# Читаем .version из нескольких мест (приоритет: _internal > app > hardcode)
for _vp in [Path(__file__).parent / ".version", BASE_DIR / ".version"]:
    try:
        if _vp.exists():
            _v = _vp.read_text(encoding="utf-8").strip()
            if _v:
                TELEPUSH_VERSION = _v
                break
    except Exception:
        pass

TELEPUSH_SERVER_URL = os.environ.get("TELEPUSH_SERVER", "https://telepush.org")

# Ссылка на саппорт — Telegram канал/юзер куда обращаться при ошибках AI-ключа,
# проблем с лицензией, общих вопросов. Можно поменять через ENV или прямо здесь.
SUPPORT_TG_URL = os.environ.get("TELEPUSH_SUPPORT_URL", "https://t.me/robi_telegram")

# Публичный ключ для верификации offline-токенов лицензии (Ed25519, raw urlsafe base64).
# Приватный ключ хранится только на лицензионном сервере (server/license_signing.key).
# Менять — только вместе с переизданием всех offline-токенов клиентам.
LICENSE_PUBLIC_KEY_B64 = "dh8TRW-yXrIJ0b_P1fGB57Xc_0rlH85lSHCCsPEbHyA="
ADMIN_IDS_RAW = os.environ.get("ADMIN_IDS", "")
DEFAULT_PROXY_URL = os.environ.get("DEFAULT_PROXY_URL", "")

# Определяем корень и DATA_DIR
_env_data = os.environ.get("TELEPUSH_DATA_DIR", "")
if _env_data:
    DATA_DIR = Path(_env_data)
    _CLIENT_ROOT = DATA_DIR.parent
elif getattr(sys, 'frozen', False):
    # frozen: определяем CLIENT_ROOT автоматически
    _exe_parent = Path(sys.executable).parent
    # Если exe в app/ → CLIENT_ROOT = app/../ (новая структура с лаунчером)
    # Если exe в корне → CLIENT_ROOT = exe_parent (старая структура без лаунчера)
    if _exe_parent.name.lower() == "app":
        _CLIENT_ROOT = _exe_parent.parent
    else:
        _CLIENT_ROOT = _exe_parent

    # Защита от расположения exe в общих папках вроде Downloads/Desktop —
    # там может уже быть папка «Аккаунты» от другого софта (Raptor, etc).
    # Если детектим — переключаемся на изолированную %APPDATA%\TelePush\.
    _SHARED_FOLDERS = {"downloads", "desktop", "documents", "pictures",
                       "music", "videos", "загрузки", "рабочий стол",
                       "документы"}
    _exe_parent_name = _CLIENT_ROOT.name.lower()
    _is_shared_location = (
        _exe_parent_name in _SHARED_FOLDERS or
        _CLIENT_ROOT == Path.home() or
        _CLIENT_ROOT.parent == Path.home() and _exe_parent_name not in {"telepush"}
    )
    if _is_shared_location:
        # Изолированный путь — никаких коллизий с чужими папками "Аккаунты"
        _CLIENT_ROOT = Path.home() / ".telepush" / "client_data"
        try:
            _CLIENT_ROOT.mkdir(parents=True, exist_ok=True)
        except Exception:
            pass

    DATA_DIR = _CLIENT_ROOT / "data"
else:
    # dev: __file__ = app/_internal/config.py
    _p = Path(__file__).parent
    while _p.name and _p.name != "app":
        _p = _p.parent
    _CLIENT_ROOT = _p.parent if _p.name == "app" else Path(__file__).parent.parent.parent
    DATA_DIR = _CLIENT_ROOT / "data"
RUNTIME_DIR = DATA_DIR

# Кириллица с fallback на латиницу
try:
    _test_dir = _CLIENT_ROOT / "\u0410\u043a\u043a\u0430\u0443\u043d\u0442\u044b"  # Аккаунты
    _test_dir.mkdir(parents=True, exist_ok=True)
    ACCOUNTS_DIR = _test_dir
    USERS_DIR    = ACCOUNTS_DIR / "\u0412 \u0440\u0430\u0431\u043e\u0442\u0435"  # В работе
except Exception:
    ACCOUNTS_DIR = _CLIENT_ROOT / "Accounts"
    USERS_DIR    = ACCOUNTS_DIR / "Active"

STAGING_DIR = DATA_DIR / "staging" / "sessions"  # создаётся по требованию
DB_PATH     = DATA_DIR / "db" / "telepush.sqlite3"
LOCK_FILE   = DATA_DIR / "telepush.lock"
LOG_DIR     = DATA_DIR / "logs"

# ── Детектим запуск из временной папки (RAR/7z без распаковки) ──
# Если exe лежит в AppData\Local\Temp\ / rartemp / 7zO — все файлы удалятся
# при закрытии архиватора. Ставим флаг — UI покажет блокирующий баннер.
_root_str = str(_CLIENT_ROOT).lower()
IS_TEMP_LAUNCH = any(m in _root_str for m in (
    r"\appdata\local\temp",
    "rartemp",
    r"\7zo",
    r"\temp\rar",
    r"\temp\7z",
))

# Экспорт — всегда рядом с TelePush.exe (портативно, всё в одной папке).
# Исключение: если exe запущен из Temp/архива — тогда в Documents/TelePush/Экспорт,
# иначе файлы пропадут при закрытии архива. Такой случай у нас уже ловится через
# IS_TEMP_LAUNCH + баннер в UI, но всё равно сохраняем хоть куда-то.
if IS_TEMP_LAUNCH:
    try:
        _docs = Path.home() / "Documents"
        if not _docs.exists():
            _docs = Path.home()
        EXPORT_DIR = _docs / "TelePush" / "\u042d\u043a\u0441\u043f\u043e\u0440\u0442"  # Экспорт
    except Exception:
        EXPORT_DIR = _CLIENT_ROOT / "\u042d\u043a\u0441\u043f\u043e\u0440\u0442"
else:
    EXPORT_DIR = _CLIENT_ROOT / "\u042d\u043a\u0441\u043f\u043e\u0440\u0442"

try:
    EXPORT_DIR.mkdir(parents=True, exist_ok=True)
except Exception:
    pass

_ALL_DIRS = [DATA_DIR, DATA_DIR / "db", LOG_DIR, USERS_DIR,
             ACCOUNTS_DIR,
             ACCOUNTS_DIR / "\u0417\u0430\u043c\u043e\u0440\u043e\u0437\u043a\u0430",     # Заморозка
             ACCOUNTS_DIR / "\u041c\u0451\u0440\u0442\u0432\u044b\u0435",               # Мёртвые
             ACCOUNTS_DIR / "\u0412 \u0441\u043f\u0430\u043c",                          # В спам
             ACCOUNTS_DIR / "\u0412\u0435\u0447\u043d\u044b\u0439 \u0441\u043f\u0430\u043c",  # Вечный спам
             ACCOUNTS_DIR / "\u041f\u0440\u043e\u0433\u0440\u0435\u0432",               # Прогрев
             ACCOUNTS_DIR / "\u0424\u0435\u0440\u043c\u0430",                           # Ферма
             ACCOUNTS_DIR / "\u0410\u0440\u0445\u0438\u0432",                           # Архив
             ACCOUNTS_DIR / "\u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438",  # После переавторизации
             ACCOUNTS_DIR / "\u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0435\u0440 tdata \u2192 session",              # Конвертер tdata → session
             ACCOUNTS_DIR / "\u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0435\u0440 session \u2192 tdata",              # Конвертер session → tdata
             ]

for _d in _ALL_DIRS:
    try:
        _d.mkdir(parents=True, exist_ok=True)
    except Exception:
        pass

# Удаляем пустые папки от прошлых версий (После инвайта, После проверки и т.п.)
_obsolete_empty = ["После инвайта", "После проверки", "После фермы", "Неверный формат"]
for _name in _obsolete_empty:
    try:
        _p = ACCOUNTS_DIR / _name
        if _p.exists() and _p.is_dir() and not any(_p.iterdir()):
            _p.rmdir()
    except Exception:
        pass

# Мигрируем аккаунты из старой английской Accounts/ в кириллическую Аккаунты/.
# Лаунчер всегда создаёт Accounts/Active/ (пустую) при запуске. Раньше тут был
# слепой rmtree(Accounts/), который СТИРАЛ аккаунты клиента если они лежали
# в Accounts/<подпапка>/ (например после старой версии или если клиент сам
# положил туда .session файлы, увидев английскую папку). Теперь: сначала
# переносим все .session/.json в соответствующую кириллическую подпапку,
# потом удаляем Accounts/ только если осталась пустой.
try:
    _old_accs = _CLIENT_ROOT / "Accounts"
    if _old_accs.exists() and _old_accs.is_dir() and ACCOUNTS_DIR.name != "Accounts":
        import shutil as _sh
        _migration_map = {
            "Active":     "В работе",      # В работе
            "Frozen":     "Заморозка",  # Заморозка
            "Dead":       "Мёртвые",       # Мёртвые
            "Spam":       "В спам",                 # В спам
            "Perma_spam": "Вечный спам",  # Вечный спам
            "Warmup":     "Прогрев",       # Прогрев
        }
        _moved_files = 0
        for _eng, _rus in _migration_map.items():
            _src_dir = _old_accs / _eng
            if not _src_dir.exists() or not _src_dir.is_dir():
                continue
            _dst_dir = ACCOUNTS_DIR / _rus
            _dst_dir.mkdir(parents=True, exist_ok=True)
            try:
                for _f in _src_dir.iterdir():
                    if not _f.is_file():
                        continue
                    # Переносим только данные аккаунтов: .session, .json, .session-journal
                    if _f.suffix not in (".session", ".json") and not _f.name.endswith("-journal"):
                        continue
                    _dst = _dst_dir / _f.name
                    if _dst.exists():
                        continue  # в новой папке уже есть — не трогаем
                    try:
                        _sh.move(str(_f), str(_dst))
                        _moved_files += 1
                    except Exception:
                        pass
            except Exception:
                pass
        # Также подхватим файлы в корне старой Accounts/ (если кто-то клал туда)
        try:
            _dst_default = ACCOUNTS_DIR / "В работе"
            _dst_default.mkdir(parents=True, exist_ok=True)
            for _f in _old_accs.iterdir():
                if _f.is_file() and (_f.suffix in (".session", ".json") or _f.name.endswith("-journal")):
                    _dst = _dst_default / _f.name
                    if not _dst.exists():
                        try:
                            _sh.move(str(_f), str(_dst))
                            _moved_files += 1
                        except Exception:
                            pass
        except Exception:
            pass
        # Теперь удаляем Accounts/ ТОЛЬКО если пустая (нет файлов аккаунтов ни на
        # одном уровне вложенности). Если что-то осталось (например нераспознанный
        # формат) — не удаляем, чтобы клиент увидел и не потерял.
        def _has_account_data(_p):
            try:
                for _item in _p.rglob("*"):
                    if _item.is_file() and (_item.suffix in (".session", ".json")):
                        return True
            except Exception:
                pass
            return False
        if not _has_account_data(_old_accs):
            try:
                _sh.rmtree(str(_old_accs), ignore_errors=True)
            except Exception:
                pass
        # Логируем через stderr (logger ещё не инициализирован здесь)
        if _moved_files:
            try:
                sys.stderr.write(
                    f"[config] Перенесено {_moved_files} файлов аккаунтов из Accounts/ в {ACCOUNTS_DIR.name}/\n"
                )
            except Exception:
                pass
except Exception:
    pass

# ── Telegram Desktop API ─────────────────────────────────────────────────────
OFFICIAL_TDESKTOP_API_ID   = 2040
OFFICIAL_TDESKTOP_APP_HASH = "b18441a1ff607e10a989891a5462e627"
OFFICIAL_TDESKTOP_LANG_PACK = "tdesktop"
DEFAULT_APP_VERSION        = "6.5.0 x64"

# ── Helpers ──────────────────────────────────────────────────────────────────
def _safe_int(key, default):
    try: return int(os.environ.get(key, str(default)))
    except (ValueError, TypeError): return default

def _safe_float(key, default):
    try: return float(os.environ.get(key, str(default)))
    except (ValueError, TypeError): return default

# ── Web ──────────────────────────────────────────────────────────────────────
WEB_PORT                = _safe_int("WEB_PORT", 8090)
WEB_SESSION_HOURS       = _safe_int("WEB_SESSION_HOURS", 720)  # 30 дней, раньше было 24ч — клиент жаловался что ключ спрашивают часто
WEB_MAX_UPLOAD_MB       = _safe_int("WEB_MAX_UPLOAD_MB", 16)
WEB_ASYNC_TIMEOUT       = _safe_int("WEB_ASYNC_TIMEOUT", 30)
API_RATE_LIMIT_PER_MIN  = _safe_int("API_RATE_LIMIT_PER_MIN", 120)
BOT_API_TIMEOUT         = _safe_int("BOT_API_TIMEOUT", 5)

# ── Captcha ──────────────────────────────────────────────────────────────────
CAPTCHA_WINDOW_SEC  = 75
CAPTCHA_CLICK_PAUSE = (1.0, 2.2)

# ── Антибан / Join ───────────────────────────────────────────────────────────
JOIN_MIN_INTERVAL_SEC   = _safe_int("JOIN_MIN_INTERVAL_SEC", 18)
JOIN_JITTER_SEC         = _safe_float("JOIN_JITTER_SEC", 3.0)
FLOODWAIT_PENALTY_FACTOR= _safe_float("FLOODWAIT_PENALTY_FACTOR", 0.33)
JOIN_MAX_PER_SESSION    = _safe_int("JOIN_MAX_PER_SESSION", 10)
JOIN_SESSION_BREAK_MIN  = _safe_float("JOIN_SESSION_BREAK_MIN", 180)
JOIN_SESSION_BREAK_MAX  = _safe_float("JOIN_SESSION_BREAK_MAX", 360)
JOIN_INVITE_PENALTY_MIN = _safe_float("JOIN_INVITE_PENALTY_MIN", 8)
JOIN_INVITE_PENALTY_MAX = _safe_float("JOIN_INVITE_PENALTY_MAX", 20)

# ── Антибан / Spam ───────────────────────────────────────────────────────────
SPAM_ANTIBAN_PARAMS = {
    "min_delay":       _safe_float("SPAM_MIN_DELAY", 6.0),
    "max_delay":       _safe_float("SPAM_MAX_DELAY", 14.0),
    "burst_size":      _safe_int("SPAM_BURST_SIZE", 7),
    "burst_pause_min": _safe_float("SPAM_BURST_PAUSE_MIN", 120.0),
    "burst_pause_max": _safe_float("SPAM_BURST_PAUSE_MAX", 240.0),
}

# ── Региональные пресеты ─────────────────────────────────────────────────────
REGION_PRESETS = {
    "UZ": {
        "label": "Узбекистан (+998)",
        "prefixes": ("998",),
        "join_min_interval": 30, "join_jitter": 5,
        "join_max_per_session": 5,
        "join_session_break_min": 300, "join_session_break_max": 600,
        "join_invite_penalty_min": 15, "join_invite_penalty_max": 30,
        "spam_min_delay": 10, "spam_max_delay": 20,
        "spam_burst_size": 4,
        "spam_burst_pause_min": 180, "spam_burst_pause_max": 360,
    },
    "TR": {
        "label": "Турция (+90)",
        "prefixes": ("90",),
        "join_min_interval": 25, "join_jitter": 4,
        "join_max_per_session": 6,
        "join_session_break_min": 240, "join_session_break_max": 480,
        "spam_min_delay": 8, "spam_max_delay": 16,
        "spam_burst_size": 5,
        "spam_burst_pause_min": 150, "spam_burst_pause_max": 300,
    },
    "MD": {
        "label": "Молдова (+373)",
        "prefixes": ("373",),
        "join_min_interval": 20, "join_jitter": 3,
        "join_max_per_session": 8,
        "join_session_break_min": 200, "join_session_break_max": 400,
        "spam_min_delay": 7, "spam_max_delay": 14,
        "spam_burst_size": 6,
        "spam_burst_pause_min": 130, "spam_burst_pause_max": 260,
    },
    "RU": {
        "label": "Россия (+7)",
        "prefixes": ("7", "79"),
        "join_min_interval": 18, "join_jitter": 3,
        "join_max_per_session": 10,
        "join_session_break_min": 180, "join_session_break_max": 360,
        "spam_min_delay": 6, "spam_max_delay": 14,
        "spam_burst_size": 7,
        "spam_burst_pause_min": 120, "spam_burst_pause_max": 240,
    },
    "DEFAULT": {
        "label": "Другой регион",
        "prefixes": (),
        "join_min_interval": JOIN_MIN_INTERVAL_SEC,
        "join_jitter": JOIN_JITTER_SEC,
        "join_max_per_session": JOIN_MAX_PER_SESSION,
        "join_session_break_min": JOIN_SESSION_BREAK_MIN,
        "join_session_break_max": JOIN_SESSION_BREAK_MAX,
        "spam_min_delay": SPAM_ANTIBAN_PARAMS["min_delay"],
        "spam_max_delay": SPAM_ANTIBAN_PARAMS["max_delay"],
        "spam_burst_size": SPAM_ANTIBAN_PARAMS["burst_size"],
        "spam_burst_pause_min": SPAM_ANTIBAN_PARAMS["burst_pause_min"],
        "spam_burst_pause_max": SPAM_ANTIBAN_PARAMS["burst_pause_max"],
    },
}

def detect_region(phone: str) -> str:
    phone = str(phone).lstrip("+")
    for code, preset in REGION_PRESETS.items():
        if code == "DEFAULT":
            continue
        for prefix in preset["prefixes"]:
            if phone.startswith(prefix):
                return code
    return "DEFAULT"

def get_region_preset(phone: str) -> dict:
    return REGION_PRESETS.get(detect_region(phone), REGION_PRESETS["DEFAULT"])
