"""
Iteration 18 backend regression tests:
- install stats payload contract
- device token registration + admin notification queueing
- world cup fixtures CRUD + auto-notification metadata
"""

from __future__ import annotations

import os
import uuid
from typing import Any, Dict, List

import pytest
import requests


BASE_URL = (os.environ.get("REACT_APP_BACKEND_URL") or "").rstrip("/")


@pytest.fixture(scope="module")
def api_client() -> requests.Session:
    session = requests.Session()
    session.headers.update({"Content-Type": "application/json"})
    return session


@pytest.fixture(scope="module")
def ensure_base_url() -> None:
    if not BASE_URL:
        pytest.skip("REACT_APP_BACKEND_URL is not set")


def _login(api_client: requests.Session, username: str, password: str) -> Dict[str, Any]:
    resp = api_client.post(
        f"{BASE_URL}/api/auth/login",
        json={"username": username, "password": password},
    )
    assert resp.status_code == 200, f"Login failed for {username}: {resp.status_code} {resp.text}"
    data = resp.json()
    assert isinstance(data.get("access_token"), str) and data["access_token"], "Missing access_token"
    assert isinstance(data.get("user"), dict), "Missing user payload"
    return data


@pytest.fixture(scope="module")
def admin_auth(api_client: requests.Session, ensure_base_url: None) -> Dict[str, Any]:
    data = _login(api_client, "admin", "admin123")
    return {
        "token": data["access_token"],
        "user_id": data["user"]["id"],
        "user": data["user"],
    }


@pytest.fixture(scope="module")
def user_0000_auth(api_client: requests.Session, ensure_base_url: None) -> Dict[str, Any]:
    data = _login(api_client, "0000", "0000")
    return {
        "token": data["access_token"],
        "user_id": data["user"]["id"],
        "user": data["user"],
    }


@pytest.fixture(scope="module")
def worldcup_snapshot(api_client: requests.Session, admin_auth: Dict[str, Any]):
    headers = {"Authorization": f"Bearer {admin_auth['token']}"}
    before = api_client.get(f"{BASE_URL}/api/worldcup/fixtures", headers=headers)
    assert before.status_code == 200, f"WorldCup GET failed before test: {before.status_code} {before.text}"
    before_data = before.json()
    existing = before_data.get("matches", [])
    assert isinstance(existing, list), "worldcup fixtures response must contain matches list"

    yield existing

    restore = api_client.post(
        f"{BASE_URL}/api/admin/worldcup/fixtures",
        headers=headers,
        json={"matches": existing},
    )
    assert restore.status_code == 200, f"WorldCup restore failed: {restore.status_code} {restore.text}"


class TestInstallStatsContract:
    """Admin install stats endpoint shape + backward compatibility fields."""

    def test_install_stats_has_legacy_and_breakdown_fields(
        self,
        api_client: requests.Session,
        admin_auth: Dict[str, Any],
    ):
        headers = {"Authorization": f"Bearer {admin_auth['token']}"}
        resp = api_client.get(f"{BASE_URL}/api/admin/stats/installs", headers=headers)
        assert resp.status_code == 200, f"Install stats failed: {resp.status_code} {resp.text}"

        data = resp.json()
        for key in [
            "total_installs",
            "active_installs",
            "dau",
            "wau",
            "total_installs_trial_devices",
            "active_installs_trial_devices_30d",
            "total_installs_fcm_tokens",
            "active_installs_fcm_tokens",
            "total_installs_merged_unique",
            "by_platform",
            "as_of",
        ]:
            assert key in data, f"Missing field: {key}"

        assert isinstance(data["total_installs"], int)
        assert isinstance(data["active_installs"], int)
        assert isinstance(data["dau"], int)
        assert isinstance(data["wau"], int)
        assert isinstance(data["by_platform"], dict)


class TestNotificationsFlow:
    """Device token registration and admin queue endpoints."""

    @pytest.fixture(scope="class")
    def registered_device(
        self,
        api_client: requests.Session,
        user_0000_auth: Dict[str, Any],
    ) -> Dict[str, str]:
        device_id = f"TEST_ITER18_DEVICE_{uuid.uuid4().hex[:10]}"
        token = f"TEST_ITER18_TOKEN_{uuid.uuid4().hex}_ABCDEFGHIJK"
        headers = {"Authorization": f"Bearer {user_0000_auth['token']}"}
        resp = api_client.post(
            f"{BASE_URL}/api/devices/register-token",
            headers=headers,
            json={
                "token": token,
                "device_id": device_id,
                "platform": "android",
                "app_version": "1.8.0-test",
            },
        )
        assert resp.status_code == 200, f"Register token failed: {resp.status_code} {resp.text}"
        payload = resp.json()
        assert payload.get("registered") is True
        assert payload.get("device_id") == device_id
        return {"device_id": device_id, "token": token}

    def test_register_device_token_logged_in_user_0000(
        self,
        registered_device: Dict[str, str],
    ):
        assert registered_device["device_id"].startswith("TEST_ITER18_DEVICE_")
        assert registered_device["token"].startswith("TEST_ITER18_TOKEN_")

    def test_admin_broadcast_notification_queues_for_active_devices(
        self,
        api_client: requests.Session,
        admin_auth: Dict[str, Any],
        registered_device: Dict[str, str],
    ):
        headers = {"Authorization": f"Bearer {admin_auth['token']}"}
        resp = api_client.post(
            f"{BASE_URL}/api/admin/broadcast-notification",
            headers=headers,
            json={
                "title": "Iter18 Broadcast",
                "body": "Broadcast queue test",
                "route": "/world-cup",
                "action_label": "Watch on",
                "data": {"kind": "iter18_broadcast"},
            },
        )
        assert resp.status_code == 200, f"Broadcast queue failed: {resp.status_code} {resp.text}"
        data = resp.json()
        assert data.get("queued") is True
        assert isinstance(data.get("total_tokens"), int) and data["total_tokens"] >= 1

    def test_admin_notify_user_queues_for_selected_user(
        self,
        api_client: requests.Session,
        admin_auth: Dict[str, Any],
        user_0000_auth: Dict[str, Any],
        registered_device: Dict[str, str],
    ):
        headers = {"Authorization": f"Bearer {admin_auth['token']}"}
        resp = api_client.post(
            f"{BASE_URL}/api/admin/notify-user",
            headers=headers,
            json={
                "title": "Iter18 User Notify",
                "body": "User-targeted queue test",
                "target_user_id": user_0000_auth["user_id"],
                "route": "/world-cup",
                "action_label": "Watch on",
                "data": {"kind": "iter18_notify_user"},
            },
        )
        assert resp.status_code == 200, f"Notify-user queue failed: {resp.status_code} {resp.text}"
        data = resp.json()
        assert data.get("queued") is True
        assert isinstance(data.get("total_tokens"), int) and data["total_tokens"] >= 1


class TestWorldCupFixturesFlow:
    """World Cup fixtures read/write + save notification metadata."""

    def test_worldcup_fixtures_get_returns_matches_array(
        self,
        api_client: requests.Session,
        ensure_base_url: None,
    ):
        resp = api_client.get(f"{BASE_URL}/api/worldcup/fixtures")
        assert resp.status_code == 200, f"WorldCup GET failed: {resp.status_code} {resp.text}"
        data = resp.json()
        assert data.get("configured") is True
        assert isinstance(data.get("matches"), list)

    def test_admin_worldcup_post_saves_and_emits_auto_notification_meta(
        self,
        api_client: requests.Session,
        admin_auth: Dict[str, Any],
        worldcup_snapshot: List[Dict[str, Any]],
    ):
        headers = {"Authorization": f"Bearer {admin_auth['token']}"}
        match_id = f"TEST_ITER18_WC_{uuid.uuid4().hex[:10]}"
        new_match = {
            "id": match_id,
            "kickoffIso": "2026-07-01T18:00:00Z",
            "status": "UPCOMING",
            "group": "Group T",
            "venue": "Iteration Stadium",
            "home": {"name": "Testland", "code": "tl"},
            "away": {"name": "QATeam", "code": "qa"},
            "homeScore": None,
            "awayScore": None,
            "broadcaster": "Test Sports 1",
            "liveLabel": "",
        }

        payload = {"matches": [*worldcup_snapshot, new_match]}
        post_resp = api_client.post(
            f"{BASE_URL}/api/admin/worldcup/fixtures",
            headers=headers,
            json=payload,
        )
        assert post_resp.status_code == 200, f"WorldCup POST failed: {post_resp.status_code} {post_resp.text}"
        data = post_resp.json()
        assert data.get("ok") is True
        assert isinstance(data.get("saved"), int) and data["saved"] >= 1
        assert isinstance(data.get("notifications"), list)

        save_notifs = [
            n
            for n in data["notifications"]
            if isinstance(n, dict)
            and isinstance(n.get("data"), dict)
            and n.get("data", {}).get("type") == "worldcup_save"
            and n.get("route") == "/world-cup"
            and n.get("action_label") == "Watch on"
        ]
        assert save_notifs, "Expected at least one worldcup_save notification metadata record"

        get_resp = api_client.get(f"{BASE_URL}/api/worldcup/fixtures")
        assert get_resp.status_code == 200, f"WorldCup GET after POST failed: {get_resp.status_code} {get_resp.text}"
        get_data = get_resp.json()
        matches = get_data.get("matches", [])
        found = [m for m in matches if isinstance(m, dict) and m.get("id") == match_id]
        assert found, f"Saved fixture id {match_id} not found in GET response"
