"""
Test migration from Akumuli to VictoriaMetrics.

This test requires both asyncakumuli and asyncvictoria packages to be installed,
as well as both akumuli and victoria-metrics binaries to be available.
"""
from __future__ import annotations

import anyio
import pytest
from contextlib import aclosing

try:
    from asyncakumuli import DS, Entry
    from asyncakumuli import connect as akumuli_connect
    from asyncakumuli.mock import AkumuliTester
    HAS_AKUMULI = True
except ImportError:
    HAS_AKUMULI = False

from asyncvictoria import DS as VDS
from asyncvictoria import Entry as VEntry
from asyncvictoria.mock import VictoriaTester


@pytest.mark.skipif(not HAS_AKUMULI, reason="asyncakumuli package not installed")
async def test_migration(free_tcp_port_factory):
    """Test migrating data from Akumuli to VictoriaMetrics."""

    # Setup test data
    test_series = "test_migration_A"  # Use underscores (Prometheus naming convention)
    test_tags = {"env": "test", "host": "localhost"}
    test_values = [
        (1500000000, 100),
        (1500000060, 200),
        (1500000120, 300),
        (1500000180, 400),
        (1500000240, 500),
    ]

    # Start Akumuli and write test data
    print("\n=== Starting Akumuli and writing test data ===")
    async with AkumuliTester(free_tcp_port_factory(), free_tcp_port_factory()).run() as akumuli:
        # Write test data to Akumuli
        for timestamp, value in test_values:
            e = Entry(
                series=test_series,
                time=timestamp,
                value=value,
                tags=test_tags,
                mode=DS.gauge,
            )
            await akumuli.put(e)

        await akumuli.flush()
        await anyio.sleep(0.5)  # Give Akumuli time to write

        # Verify data was written to Akumuli
        print("=== Verifying data in Akumuli ===")
        count = 0
        # Use a smaller time range that covers our test data (1500000000 to 1500000240)
        gd = akumuli.get_data(test_series, tags=test_tags, t_start=1499999000, t_end=1500001000)
        async with aclosing(gd):
            async for x in gd:
                print(f"  Akumuli has: {x.time} = {x.value}")
                count += 1

        assert count == len(test_values), f"Expected {len(test_values)} points in Akumuli, got {count}"
        print(f"✓ Akumuli has {count} data points")

        # Start VictoriaMetrics and migrate data
        print("\n=== Starting VictoriaMetrics and migrating data ===")
        async with VictoriaTester(free_tcp_port_factory(), free_tcp_port_factory()).run() as victoria:
            # Migrate data from Akumuli to VictoriaMetrics
            print("=== Starting migration ===")

            # Read from Akumuli
            gd = akumuli.get_data(test_series, tags=test_tags, t_start=1490000000, t_end=1510000000)
            migrated_count = 0

            async with aclosing(gd):
                async for akumuli_entry in gd:
                    # Create VictoriaMetrics entry
                    victoria_entry = VEntry(
                        value=akumuli_entry.value,
                        series=akumuli_entry.series,
                        time=akumuli_entry.time,
                        tags=akumuli_entry.tags,
                        mode=VDS.gauge,
                    )
                    await victoria.put(victoria_entry)
                    migrated_count += 1
                    print(f"  Migrated: {victoria_entry.time} = {victoria_entry.value}")

            await victoria.flush()
            await victoria.force_flush()  # Force VictoriaMetrics to flush all pending data

            print(f"✓ Migrated {migrated_count} data points")

            # Verify data was written to VictoriaMetrics
            print("\n=== Verifying data in VictoriaMetrics ===")
            victoria_count = 0
            victoria_values = []

            # Use the same time range as for Akumuli
            # Query without tag filter (VictoriaMetrics will return all tags for this series)
            gd = victoria.get_data(test_series, tags={}, t_start=1499999000, t_end=1500001000)
            async with aclosing(gd):
                async for x in gd:
                    print(f"  VictoriaMetrics has: {x.time} = {x.value}")
                    victoria_count += 1
                    victoria_values.append((int(x.time), int(x.value)))

            print(f"✓ VictoriaMetrics has {victoria_count} data points")

            # Verify counts match
            assert victoria_count == len(test_values), \
                f"Expected {len(test_values)} points in VictoriaMetrics, got {victoria_count}"

            # Verify values match (allowing for timestamp alignment by VictoriaMetrics)
            # Sort both lists since order might differ
            expected_values = [(int(t), int(v)) for t, v in test_values]
            expected_values.sort()
            victoria_values.sort()

            # Check that each value exists with approximately the right timestamp
            for (exp_t, exp_v), (got_t, got_v) in zip(expected_values, victoria_values, strict=False):
                assert got_v == exp_v, f"Value mismatch: expected {exp_v}, got {got_v}"
                # Allow timestamp drift due to VictoriaMetrics alignment (within 60 seconds)
                assert abs(got_t - exp_t) < 60, \
                    f"Timestamp mismatch: expected ~{exp_t}, got {got_t}"

            print("\n✓ Migration test passed! All data migrated correctly.")


@pytest.mark.skipif(not HAS_AKUMULI, reason="asyncakumuli package not installed")
async def test_migration_with_multiple_series(free_tcp_port_factory):
    """Test migrating multiple series from Akumuli to VictoriaMetrics."""

    test_data = [
        ("cpu_usage", {"host": "server1"}, [(1500000000 + i*60, 10 + i) for i in range(5)]),
        ("memory_usage", {"host": "server1"}, [(1500000000 + i*60, 100 + i*10) for i in range(5)]),
        ("disk_usage", {"host": "server2"}, [(1500000000 + i*60, 50 + i*5) for i in range(5)]),
    ]

    print("\n=== Testing migration of multiple series ===")

    # Start Akumuli and write test data
    async with AkumuliTester(free_tcp_port_factory(), free_tcp_port_factory()).run() as akumuli:
        # Write test data for all series
        for series, tags, values in test_data:
            for timestamp, value in values:
                e = Entry(
                    series=series,
                    time=timestamp,
                    value=value,
                    tags=tags,
                    mode=DS.gauge,
                )
                await akumuli.put(e)

        await akumuli.flush()
        await anyio.sleep(0.5)

        # Start VictoriaMetrics and migrate
        async with VictoriaTester(free_tcp_port_factory(), free_tcp_port_factory()).run() as victoria:
            # Migrate each series
            for series, tags, expected_values in test_data:
                print(f"\n  Migrating {series} with tags {tags}")

                # Read from Akumuli (data ranges from 1500000000 to 1500000240)
                gd = akumuli.get_data(series, tags=tags, t_start=1499999000, t_end=1500001000)
                count = 0

                async with aclosing(gd):
                    async for akumuli_entry in gd:
                        victoria_entry = VEntry(
                            series=akumuli_entry.series,
                            time=akumuli_entry.time,
                            value=akumuli_entry.value,
                            tags=akumuli_entry.tags,
                            mode=VDS.gauge,
                        )
                        await victoria.put(victoria_entry)
                        count += 1

                print(f"    Migrated {count} points for {series}")

            await victoria.flush()
            await victoria.force_flush()  # Force VictoriaMetrics to flush all pending data

            # Verify all series
            for series, tags, expected_values in test_data:
                print(f"\n  Verifying {series}")

                # Use the same time range as for reading from Akumuli
                # Query without tag filter (VictoriaMetrics will return all tags for this series)
                gd = victoria.get_data(series, tags={}, t_start=1499999000, t_end=1500001000)
                count = 0

                async with aclosing(gd):
                    async for x in gd:
                        count += 1

                assert count == len(expected_values), \
                    f"Expected {len(expected_values)} points for {series}, got {count}"
                print(f"    ✓ Verified {count} points for {series}")

            print("\n✓ Multi-series migration test passed!")
