"""Telemetry beacon: payload shape, anonymity and bucketing.

These tests never touch the network or a database: ``_build_payload`` is given
a ``None`` session (the user-count lookup degrades to 0) and a fixed install id,
so we can assert the PostHog-shaped envelope and that no secrets leak.
"""

import asyncio
import json

import pytest

from bot.services.telemetry_worker import HEARTBEAT_EVENT, TelemetryWorker, _bucket_users
from config.settings import Settings


@pytest.fixture
def settings(monkeypatch) -> Settings:
    # Provide the minimal required env so Settings() validates without a .env,
    # keeping the test self-contained in CI.
    monkeypatch.setenv("BOT_TOKEN", "1234567890:AA_secret_bot_token_value")
    monkeypatch.setenv("POSTGRES_USER", "u")
    monkeypatch.setenv("POSTGRES_PASSWORD", "Sup3rSecretDbPassw0rd")
    monkeypatch.setenv("POSTGRES_DB", "d")
    monkeypatch.setenv("ADMIN_IDS", "1")
    return Settings()


def test_bucket_users_boundaries():
    assert _bucket_users(0) == "0"
    assert _bucket_users(1) == "1-10"
    assert _bucket_users(10) == "1-10"
    assert _bucket_users(11) == "11-50"
    assert _bucket_users(50) == "11-50"
    assert _bucket_users(200) == "51-200"
    assert _bucket_users(1000) == "201-1000"
    assert _bucket_users(5000) == "1001-5000"
    assert _bucket_users(5001) == "5000+"
    assert _bucket_users(99999) == "5000+"


def test_build_payload_shape(settings):
    worker = TelemetryWorker(settings, None)
    payload = asyncio.run(worker._build_payload(None, "install-123"))

    assert payload["event"] == HEARTBEAT_EVENT
    assert payload["distinct_id"] == "install-123"
    assert payload["api_key"] == settings.TELEMETRY_API_KEY.strip()

    props = payload["properties"]
    for key in (
        "app_version",
        "app_version_tag",
        "os",
        "arch",
        "python_version",
        "locale",
        "users_bucket",
        "payment_providers",
        "webapp_enabled",
        "panel_configured",
    ):
        assert key in props, f"missing property: {key}"

    assert isinstance(props["payment_providers"], list)
    # No DB session -> user count degrades to the smallest bucket.
    assert props["users_bucket"] == "0"
    # Person properties mirror the event properties so PostHog breakdowns work.
    assert props["$set"]["app_version"] == props["app_version"]
    assert props["$lib"] == "remnawave-minishop"


def test_payload_contains_no_secrets_or_pii(settings):
    worker = TelemetryWorker(settings, None)
    payload = asyncio.run(worker._build_payload(None, "install-123"))
    blob = json.dumps(payload)

    # The bot token and DB password must never appear in the beacon.
    assert settings.BOT_TOKEN not in blob
    assert settings.POSTGRES_PASSWORD not in blob


def test_delivery_disabled_without_endpoint_or_key(settings, monkeypatch):
    worker = TelemetryWorker(settings, None)
    assert worker._delivery_configured() is True

    monkeypatch.setattr(settings, "TELEMETRY_API_KEY", "", raising=False)
    assert worker._delivery_configured() is False

    monkeypatch.setattr(settings, "TELEMETRY_API_KEY", "phc_x", raising=False)
    monkeypatch.setattr(settings, "TELEMETRY_ENDPOINT", "", raising=False)
    assert worker._delivery_configured() is False
