"""Tests for verifier modules (mocked HTTP)."""

import json
from unittest.mock import patch, MagicMock
import pytest

from x402_stacks.verifier import X402PaymentVerifierV1, SettleOptionsV1
from x402_stacks.verifier_v2 import X402PaymentVerifier, VerifyOptions, SettleOptions, create_verifier
from x402_stacks.types import VerificationOptions
from x402_stacks.types_v2 import (
    PaymentPayloadV2,
    PaymentRequirementsV2,
    StacksPayloadV2,
)


class TestV1Verifier:
    def _make_mock_response(self, data: dict, status: int = 200):
        """Create a mock urllib response."""
        mock = MagicMock()
        mock.read.return_value = json.dumps(data).encode()
        mock.status = status
        mock.__enter__ = MagicMock(return_value=mock)
        mock.__exit__ = MagicMock(return_value=False)
        return mock

    @patch("urllib.request.urlopen")
    def test_verify_payment_success(self, mock_urlopen):
        mock_urlopen.return_value = self._make_mock_response({
            "valid": True,
            "tx_id": "abc123",
            "sender_address": "ST1",
            "recipient_address": "ST2",
            "amount": 1000000,
            "status": "confirmed",
        })

        verifier = X402PaymentVerifierV1("http://test:8085", "testnet")
        opts = VerificationOptions(
            expected_recipient="ST2",
            min_amount=1000000,
        )
        result = verifier.verify_payment("abc123", opts)
        assert result.is_valid is True
        assert result.tx_id == "abc123"

    @patch("urllib.request.urlopen")
    def test_settle_payment_success(self, mock_urlopen):
        mock_urlopen.return_value = self._make_mock_response({
            "success": True,
            "tx_id": "abc123",
            "sender_address": "ST1",
            "recipient_address": "ST2",
            "amount": 1000000,
            "status": "confirmed",
        })

        verifier = X402PaymentVerifierV1("http://test:8085", "testnet")
        opts = SettleOptionsV1(
            expected_recipient="ST2",
            min_amount=1000000,
        )
        result = verifier.settle_payment("deadbeef", opts)
        assert result.is_valid is True

    def test_is_payment_valid_returns_bool(self):
        verifier = X402PaymentVerifierV1("http://nonexistent:9999", "testnet")
        opts = VerificationOptions(
            expected_recipient="ST2",
            min_amount=1000000,
        )
        # Will fail due to network error, should return False
        result = verifier.is_payment_valid("abc123", opts)
        assert result is False


class TestV2Verifier:
    def _make_mock_response(self, data: dict, status: int = 200):
        mock = MagicMock()
        mock.read.return_value = json.dumps(data).encode()
        mock.status = status
        mock.__enter__ = MagicMock(return_value=mock)
        mock.__exit__ = MagicMock(return_value=False)
        return mock

    def _make_requirements(self):
        return PaymentRequirementsV2(
            scheme="exact",
            network="stacks:2147483648",
            amount="1000000",
            asset="STX",
            pay_to="ST123",
            max_timeout_seconds=300,
        )

    def _make_payload(self):
        return PaymentPayloadV2(
            x402_version=2,
            accepted=self._make_requirements(),
            payload=StacksPayloadV2(transaction="deadbeef"),
        )

    @patch("urllib.request.urlopen")
    def test_verify_success(self, mock_urlopen):
        mock_urlopen.return_value = self._make_mock_response({
            "isValid": True,
            "payer": "ST456",
        })

        verifier = X402PaymentVerifier("http://test:8085")
        result = verifier.verify(
            self._make_payload(),
            VerifyOptions(payment_requirements=self._make_requirements()),
        )
        assert result.is_valid is True
        assert result.payer == "ST456"

    @patch("urllib.request.urlopen")
    def test_settle_success(self, mock_urlopen):
        mock_urlopen.return_value = self._make_mock_response({
            "success": True,
            "transaction": "0xabc",
            "network": "stacks:2147483648",
            "payer": "ST456",
        })

        verifier = X402PaymentVerifier("http://test:8085")
        result = verifier.settle(
            self._make_payload(),
            SettleOptions(payment_requirements=self._make_requirements()),
        )
        assert result.success is True

    @patch("urllib.request.urlopen")
    def test_get_supported(self, mock_urlopen):
        mock_urlopen.return_value = self._make_mock_response({
            "kinds": [{"x402Version": 2, "scheme": "exact", "network": "stacks:1"}],
            "extensions": [],
            "signers": {},
        })

        verifier = X402PaymentVerifier("http://test:8085")
        result = verifier.get_supported()
        assert len(result.kinds) == 1

    def test_create_verifier(self):
        v = create_verifier("http://test:8085")
        assert isinstance(v, X402PaymentVerifier)

    def test_create_payment_payload(self):
        reqs = self._make_requirements()
        payload = X402PaymentVerifier.create_payment_payload("deadbeef", reqs)
        assert payload.x402_version == 2
        assert payload.payload.transaction == "deadbeef"
