#!/usr/bin/env python3
"""
Tests for ``mmv.fetch_versions`` (a thin re-export of
``asc_version_fetch.fetch_versions``).

Covers pagination, the explicit ``filter[platform]=IOS`` query param,
the ``limit=200`` (ASC max) request shape, and the per-record stderr
logging used by the CI debug trace. These were factored out of
``test_mmv_floor_check.py`` to keep that module under the 400-line
cap while preserving every assertion.
"""

from __future__ import annotations

import io
import sys
import unittest
from contextlib import redirect_stderr
from pathlib import Path
from unittest import mock

sys.path.insert(0, str(Path(__file__).resolve().parent))

import manage_marketing_version as mmv  # noqa: E402
import asc_version_fetch  # noqa: E402

from tests_common import _FakeResponse  # noqa: E402


def _asv_record(
    vid: str, version: str, state: str, created: str,
) -> dict:
    """Build a /v1/apps/{id}/appStoreVersions data entry."""
    return {
        "id": vid,
        "attributes": {
            "versionString": version,
            "appStoreState": state,
            "platform": "IOS",
            "createdDate": created,
        },
    }


class FetchVersionsPaginationTests(unittest.TestCase):
    """fetch_versions MUST follow links.next to exhaustion."""

    def test_fetch_is_paginated(self):
        page1 = {
            "data": [
                _asv_record("id-1.0", "1.0", "READY_FOR_SALE",
                            "2025-01-01T00:00:00Z"),
                _asv_record("id-1.0.1", "1.0.1", "PREPARE_FOR_SUBMISSION",
                            "2025-02-01T00:00:00Z"),
            ],
            "links": {
                "next": "https://api.appstoreconnect.apple.com/v1/apps/111/"
                        "appStoreVersions?cursor=PAGE2",
            },
        }
        page2 = {
            "data": [
                _asv_record("id-1.0.4", "1.0.4", "READY_FOR_SALE",
                            "2025-04-01T00:00:00Z"),
            ],
            "links": {},
        }
        responses = [_FakeResponse(page1), _FakeResponse(page2)]

        def fake_request(method, path, token, *, params=None, **_kw):
            return responses.pop(0)

        with mock.patch.object(asc_version_fetch, "request", side_effect=fake_request):
            got = mmv.fetch_versions("111", "tok")

        versions = {v["versionString"] for v in got}
        self.assertIn("1.0.4", versions)
        self.assertIn("1.0", versions)
        self.assertIn("1.0.1", versions)
        self.assertEqual(len(responses), 0, "both pages must be consumed")


class FetchVersionsPlatformFilterTests(unittest.TestCase):
    """fetch_versions MUST pass filter[platform]=IOS."""

    def test_platform_filter_applied(self):
        seen_params: list[dict | None] = []

        def fake_request(method, path, token, *, params=None, **_kw):
            seen_params.append(params)
            return _FakeResponse({"data": [], "links": {}})

        with mock.patch.object(asc_version_fetch, "request", side_effect=fake_request):
            mmv.fetch_versions("111", "tok")

        self.assertTrue(seen_params)
        first = seen_params[0] or {}
        self.assertEqual(first.get("filter[platform]"), "IOS")


class FetchVersionsLimitTests(unittest.TestCase):
    """fetch_versions MUST request limit=200 (ASC max)."""

    def test_limit_200_requested(self):
        seen_params: list[dict | None] = []

        def fake_request(method, path, token, *, params=None, **_kw):
            seen_params.append(params)
            return _FakeResponse({"data": [], "links": {}})

        with mock.patch.object(asc_version_fetch, "request", side_effect=fake_request):
            mmv.fetch_versions("111", "tok")

        first = seen_params[0] or {}
        self.assertEqual(first.get("limit"), 200)


class FetchVersionsLoggingTests(unittest.TestCase):
    """Every fetched record MUST be logged to stderr."""

    def test_every_record_logged(self):
        page1 = {
            "data": [
                {
                    "id": "id-1.0.4",
                    "attributes": {
                        "versionString": "1.0.4",
                        "appStoreState": "READY_FOR_SALE",
                        "platform": "IOS",
                        "createdDate": "2025-04-01T00:00:00Z",
                    },
                },
                {
                    "id": "id-1.0.1",
                    "attributes": {
                        "versionString": "1.0.1",
                        "appStoreState": "PREPARE_FOR_SUBMISSION",
                        "platform": "IOS",
                        "createdDate": "2025-02-01T00:00:00Z",
                    },
                },
            ],
            "links": {},
        }

        def fake_request(method, path, token, *, params=None, **_kw):
            return _FakeResponse(page1)

        buf = io.StringIO()
        with mock.patch.object(asc_version_fetch, "request", side_effect=fake_request), \
                redirect_stderr(buf):
            mmv.fetch_versions("111", "tok")

        stderr = buf.getvalue()
        self.assertIn("1.0.4", stderr)
        self.assertIn("READY_FOR_SALE", stderr)
        self.assertIn("id-1.0.4", stderr)
        self.assertIn("1.0.1", stderr)
        self.assertIn("PREPARE_FOR_SUBMISSION", stderr)


if __name__ == "__main__":
    unittest.main()
