"""Integration tests against the live 0byte API.

Run with: pytest tests/test_integration.py -v
Requires: ZEROBYTE_API_KEY environment variable set.
"""

import io
import os
import pytest
from zerobyte import Client
from zerobyte.exceptions import AuthenticationError, ProofError

API_KEY = os.environ.get("ZEROBYTE_API_KEY")
ENDPOINT = os.environ.get("ZEROBYTE_ENDPOINT", "https://api.0byte.tech")


def _make_test_png(width=64, height=64):
    """Generate a valid PNG image in memory using pure Python (no PIL needed)."""
    import struct
    import zlib

    def chunk(chunk_type, data):
        c = chunk_type + data
        return struct.pack(">I", len(data)) + c + struct.pack(">I", zlib.crc32(c) & 0xFFFFFFFF)

    header = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0)  # 8-bit RGB
    # Generate simple gradient pixel data
    raw = b""
    for y in range(height):
        raw += b"\x00"  # filter byte
        for x in range(width):
            raw += bytes([x * 4 % 256, y * 4 % 256, 128])  # RGB
    compressed = zlib.compress(raw)

    png = b"\x89PNG\r\n\x1a\n"
    png += chunk(b"IHDR", header)
    png += chunk(b"IDAT", compressed)
    png += chunk(b"IEND", b"")
    return png


TEST_PNG = _make_test_png()

pytestmark = pytest.mark.skipif(
    not API_KEY, reason="ZEROBYTE_API_KEY not set"
)


@pytest.fixture
def client():
    with Client(api_key=API_KEY, endpoint=ENDPOINT) as c:
        yield c


@pytest.fixture
def anon_client():
    """Client without API key — for public endpoints."""
    with Client(endpoint=ENDPOINT) as c:
        yield c


class TestHealthCheck:
    def test_health(self, anon_client):
        """API should be reachable."""
        resp = anon_client._http.get(f"{ENDPOINT}/v1/health")
        assert resp.status_code == 200
        data = resp.json()
        assert data["status"] == "ok"
        assert data["service"] == "0byte"
        assert "public_key" in data


class TestStampAndVerify:
    def test_stamp_creates_proof(self, client):
        proof = client.stamp(
            content=TEST_PNG,
            content_type="image/png",
            provider="test-suite",
            model="integration-test",
        )

        assert proof.id.startswith("0b_")
        assert len(proof.fingerprint) > 0
        assert proof.provider == "test-suite"
        assert proof.model == "integration-test"
        assert proof.content_type == "image/png"
        assert proof.signature
        assert proof.verify_url

    def test_stamp_then_verify(self, client):
        """Stamp content, then verify it matches."""
        proof = client.stamp(
            content=TEST_PNG,
            content_type="image/png",
            provider="test-suite",
            model="e2e-verify",
        )

        result = client.verify(content=TEST_PNG, content_type="image/png")

        assert result.matched is True
        assert result.confidence > 0.8
        assert result.proof is not None
        assert result.proof.fingerprint == proof.fingerprint

    def test_stamp_then_lookup(self, client):
        """Stamp content, then look it up by ID."""
        proof = client.stamp(
            content=TEST_PNG,
            content_type="image/png",
            provider="test-suite",
            model="e2e-lookup",
        )

        looked_up = client.get_proof(proof.id)

        assert looked_up.id == proof.id
        assert looked_up.fingerprint == proof.fingerprint
        assert looked_up.provider == proof.provider

    def test_stamp_with_metadata(self, client):
        proof = client.stamp(
            content=TEST_PNG,
            content_type="image/png",
            provider="test-suite",
            model="metadata-test",
            metadata={"test_run": True, "suite": "integration"},
        )

        assert proof.metadata == {"test_run": True, "suite": "integration"}


class TestVerifyPublic:
    def test_verify_without_api_key(self, anon_client):
        """Verify endpoint should work without authentication."""
        result = anon_client.verify(content=TEST_PNG, content_type="image/png")
        # May or may not match depending on whether stamp tests ran first
        assert isinstance(result.matched, bool)
        assert isinstance(result.confidence, float)


class TestErrorCases:
    def test_stamp_bad_api_key(self):
        with Client(api_key="0b_key_invalid", endpoint=ENDPOINT) as client:
            with pytest.raises(AuthenticationError):
                client.stamp(TEST_PNG, "image/png", "test", "test")

    def test_get_proof_not_found(self, anon_client):
        with pytest.raises(ProofError, match="Proof not found"):
            anon_client.get_proof("0b_nonexistent-proof-id")
