import os
import warnings

from pydantic import model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")

    database_url: str = "postgresql+psycopg://gendesign:gendesign@localhost:5432/gendesign"
    redis_url: str = "redis://localhost:6379/0"
    cors_origins: list[str] = ["http://localhost:3000"]
    # GlitchTip error tracking (Sentry-compatible self-hosted).
    # Формат DSN: https://<key>@errors.gendsgn.ru/<project_id>
    # Пустая строка / None = SDK не инициализируется (no-op).
    glitchtip_dsn: str | None = None
    glitchtip_traces_sample_rate: float = 0.05
    environment: str = "dev"

    @model_validator(mode="after")
    def _promote_legacy_sentry_dsn(self) -> "Settings":
        """Backward-compat: legacy SENTRY_DSN → glitchtip_dsn ТОЛЬКО для self-hosted.

        Старый VPS .env.runtime мог содержать SENTRY_DSN=https://...@sentry.io/...
        (legacy SaaS Sentry). Промоутить его НЕЛЬЗЯ — события пойдут в чужой проект.
        Принимаем только URLs указывающие на наш errors.gendsgn.ru host.
        """
        if not self.glitchtip_dsn:
            legacy = os.getenv("SENTRY_DSN")
            if legacy:
                if "errors.gendsgn.ru" in legacy:
                    warnings.warn(
                        "SENTRY_DSN is set but ignored by pydantic; rename to GLITCHTIP_DSN. "
                        "Auto-promoting for backward compat.",
                        DeprecationWarning,
                        stacklevel=2,
                    )
                    self.glitchtip_dsn = legacy
                else:
                    warnings.warn(
                        f"SENTRY_DSN points to non-GlitchTip host "
                        f"({legacy.split('@', 1)[-1][:40]}...) — ignoring. "
                        "Set GLITCHTIP_DSN explicitly.",
                        UserWarning,
                        stacklevel=2,
                    )
        return self

    # External APIs (Stage 2)
    rosreestr_pkk_base_url: str = "https://pkk.rosreestr.ru/api/features/1"
    overpass_url: str = "https://overpass-api.de/api/interpreter"

    # Scraper schedule (наш.дом.рф kn-API).
    # Crontab format: "minute hour day_of_month month day_of_week" (Celery crontab).
    # Default: каждый понедельник в окне 04:00–05:00 по МСК.
    scrape_kn_cron: str = "15 4 * * mon"
    # Random delay window in seconds added on top of scheduled start so the worker
    # does not hit DOM.РФ at exactly the same minute every cycle. 0 = disabled.
    scrape_kn_jitter_seconds: int = 1800
    # Default region(s) for scheduled sweeps. Comma-separated.
    scrape_kn_default_regions: str = "66"
    # Path to a pre-captured Playwright storage_state.json (committed in repo,
    # used by worker to skip cold-start WAF challenge).
    scrape_kn_state_path: str = "data/playwright_state.json"
    # Token to authorize ad-hoc /api/v1/admin/scrape/* trigger calls.
    # Empty string = endpoint disabled.
    scrape_admin_token: str = ""

    # NSPD-scraper (Playwright) УДАЛЁН 2026-05-11. Сменён на bulk geo-fetcher
    # через rosreestr2coord — запускается вручную через /admin/scrape/geo.
    # Settings оставлены deprecated на случай отката (можно удалить позже).
    scrape_nspd_cron: str = "30 3 20 2,5,8,11 *"  # DEPRECATED
    scrape_nspd_default_regions: str = "66"  # DEPRECATED
    scrape_nspd_rate_ms: int = 600  # DEPRECATED — see nspd_lite_rate_ms

    # Objective.ru API (api.objctv.ru) — платная аналитика первички/вторички.
    # Лежит наряду с DOM.РФ kn + rosreestr CSV как 3-й источник истины с
    # самой богатой моделью (per-flat per-day, escrow/банк-долг, ЕГРН-ИНН).
    # Получить ключ: личный закрытый ApiKey от Объектива (тариф per-территория).
    # Tank-схема:
    #   1. GET /Users/User/GetToken?apiKey=<KEY> → JSON с Bearer-токеном
    #   2. GET /v2/Report/GetReport?... + Authorization: Bearer <token>
    objective_api_key: str | None = None
    objective_base_url: str = "https://api.objctv.ru"
    # Группа = «настройка территории» внутри Объектива. Чаще всего совпадает с
    # городом/областью. Доступные группы определяются тарифом ключа.
    objective_default_group: str = "Екатеринбург"
    # Список групп для еженедельного auto-sync (csv). Эмпирически проверено
    # 2026-05-10 что эти группы доступны на нашем тарифе:
    #   - "Свердловская область" → 1626 corp_sum/3д (= ЕКБ + спутники + регион)
    #   - "Челябинск" → 355
    #   - "Тюмень" → 985
    #   - "Пермь" → 423
    # Стратегия Variant B (включить наш sync параллельно Антоновому ETL):
    # Антон тянет только Екб (303k lots). Наш sync даёт +30k Свердл.обл
    # за пределами Екб + ~700k квартир УрФО (Челябинск, Тюмень, Пермь).
    # Итог в PG: ~1М квартир уральского + западносибирского рынка.
    # Между группами task делает паузу _OBJECTIVE_INTER_GROUP_DELAY = 30с
    # чтобы не упереться в rate-limit Объектива.
    objective_sync_groups: str = "Свердловская область,Челябинск,Тюмень,Пермь"
    # Токен Bearer короткоживущий (предположительно 30 мин — уточнить).
    # Кешируем в Redis с этим TTL (с запасом 5 мин).
    objective_token_ttl_seconds: int = 25 * 60
    # Расписание sync — еженедельно по вторникам в 06:00 МСК.
    # ПОЧЕМУ ВТОРНИК (а не понедельник как раньше): Антон тянет в понедельник,
    # к утру вторника его SQLite уже обновлён — наш sync захватывает свежий
    # snapshot за тот же отчётный период.
    objective_sync_cron: str = "0 6 * * tue"

    # NSPD lite (urllib через WAF) — feature toggle для переключения с
    # Playwright-based nspd_kn.py на минималистичный nspd_lite.py.
    # 2026-05-11: эмпирически проверено что urllib проходит WAF nspd.gov.ru
    # (TLS-fingerprint stdlib не блокируется). Старый Playwright-путь
    # остаётся как fallback на случай возврата WAF-проблем.
    use_nspd_lite: bool = True
    # Default rate-limit для nspd_lite fetcher (мс между запросами).
    nspd_lite_rate_ms: int = 600

    # ETL Антоновского /sf/api/* SQLite → нашу PG (objective_* таблицы).
    # На проде монтируется bind-mount-ом docker-compose:
    #   /opt/gendesign/site-finder/analysis.db -> /data/anton-sqlite/analysis.db
    # Триггерится вручную через POST /api/v1/admin/scrape/objective.
    # Для локальной разработки — указать абсолютный путь к скачанному snapshot:
    #   OBJECTIVE_ANTON_SQLITE_PATH=C:/Users/user/source/repos/gendesign/sf_anton_snapshot.db
    objective_anton_sqlite_path: str = "/data/anton-sqlite/analysis.db"

    # OpenRouteService API (https://openrouteservice.org/dev/#/signup).
    # Free tier: 2000 запросов/день. Используется в /parcels/{cad}/isochrones.
    # Если не задан — endpoint вернёт 503 с инструкцией по регистрации.
    openrouteservice_api_key: str = ""


settings = Settings()
