import pytest
from fastapi.testclient import TestClient

from py_ipfs_lite.api import app


@pytest.fixture
def client():
    return TestClient(app)


def test_metrics_endpoint(client):
    from unittest.mock import Mock

    mock_peer = Mock()
    mock_network = Mock()
    mock_network.connections = {}
    mock_peer.host.get_network.return_value = mock_network
    mock_peer.host._host.get_network.return_value = mock_network
    app.state.peer = mock_peer

    for endpoint in ("/metrics", "/debug/metrics/prometheus"):
        response = client.get(endpoint)
        assert response.status_code == 200
        content = response.text

        assert "ipfs_blockstore_blocks_total" in content
        assert "ipfs_gc_runs_total" in content
        assert "ipfs_dht_query_latency_seconds" in content
        assert "ipfs_bitswap_bytes_received_total" in content
        assert "ipfs_swarm_peers" in content
        assert "ipfs_swarm_connections_total" in content
        assert "ipfs_process_cpu_percent" in content
        assert "ipfs_process_memory_rss_bytes" in content
        assert "ipfs_process_uptime_seconds" in content


@pytest.mark.trio
async def test_metrics_idempotent_put():
    from py_ipfs_lite.config import Config
    from py_ipfs_lite.metrics import IPFS_BLOCKSTORE_BLOCKS_TOTAL
    from py_ipfs_lite.peer import Peer

    before_count = IPFS_BLOCKSTORE_BLOCKS_TOTAL._value.get()

    config = Config(offline=True, blockstore_type="memory")
    async with Peer(config, listen_addrs=["/ip4/127.0.0.1/tcp/0"]) as peer:
        # Add the same file twice
        await peer.add_file(b"idempotent content test")
        await peer.add_file(b"idempotent content test")

    after_count = IPFS_BLOCKSTORE_BLOCKS_TOTAL._value.get()
    # Adding a file adds exactly 1 block in this case, but adding it twice should still be just 1 block added.
    assert after_count == before_count + 1


@pytest.mark.trio
async def test_metrics_idempotent_delete():
    from py_ipfs_lite.config import Config
    from py_ipfs_lite.metrics import IPFS_BLOCKSTORE_BLOCKS_TOTAL
    from py_ipfs_lite.peer import Peer

    before_count = IPFS_BLOCKSTORE_BLOCKS_TOTAL._value.get()

    config = Config(offline=True, blockstore_type="memory")
    async with Peer(config, listen_addrs=["/ip4/127.0.0.1/tcp/0"]) as peer:
        # Attempt to remove a CID that doesn't exist
        fake_cid_str = "bafyreigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
        try:
            await peer.remove_node(fake_cid_str)
        except Exception:
            pass

    after_count = IPFS_BLOCKSTORE_BLOCKS_TOTAL._value.get()
    assert after_count == before_count


@pytest.mark.trio
async def test_libp2p_event_bus_metrics_attached():
    """Real Peer attaches the libp2p event-bus metrics; families render."""
    from prometheus_client import generate_latest

    from py_ipfs_lite.config import Config
    from py_ipfs_lite.peer import Peer

    config = Config(offline=True, blockstore_type="memory")
    async with Peer(config, listen_addrs=["/ip4/127.0.0.1/tcp/0"]) as peer:
        assert peer.libp2p_metrics is not None
        body = generate_latest().decode()
        assert "bitswap_wantlist_adds_total" in body
        assert "kad_lookup_total" in body


@pytest.mark.trio
async def test_libp2p_event_bus_metrics_disabled(monkeypatch):
    """IPFS_LITE_ENABLE_LIBP2P_METRICS=0 skips the attach."""
    from py_ipfs_lite.config import Config
    from py_ipfs_lite.peer import Peer

    monkeypatch.setenv("IPFS_LITE_ENABLE_LIBP2P_METRICS", "0")
    config = Config(offline=True, blockstore_type="memory")
    assert config.enable_libp2p_metrics is False
    async with Peer(config, listen_addrs=["/ip4/127.0.0.1/tcp/0"]) as peer:
        assert peer.libp2p_metrics is None
