"""Tests for EIP-712 payment signing (x402 module).

Verifies that:
1. USDC amount parsing is correct (6 decimals)
2. EIP-712 signatures are valid and recoverable
3. Output matches x402 PaymentPayload v2 format
"""

from eth_account import Account

from oneshot.x402 import (
    _parse_usdc_amount,
    build_zero_cost_authorization,
    encode_payment_header,
    sign_payment_authorization,
)

# Deterministic test key (never use with real funds)
TEST_PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
TEST_ADDRESS = Account.from_key(TEST_PRIVATE_KEY).address

# Base Mainnet config
CHAIN_ID = 8453
USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
TO_ADDRESS = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"

MOCK_ACCEPTED = {
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "1000000",
    "asset": USDC_ADDRESS,
    "payTo": TO_ADDRESS,
    "maxTimeoutSeconds": 300,
    "extra": {"name": "USD Coin", "version": "2"},
}


class TestParseUsdcAmount:
    def test_whole_number(self) -> None:
        assert _parse_usdc_amount("10") == 10_000_000

    def test_two_decimals(self) -> None:
        assert _parse_usdc_amount("1.50") == 1_500_000

    def test_six_decimals(self) -> None:
        assert _parse_usdc_amount("0.000001") == 1

    def test_three_decimals(self) -> None:
        assert _parse_usdc_amount("0.123") == 123_000

    def test_zero(self) -> None:
        assert _parse_usdc_amount("0") == 0

    def test_small_amount(self) -> None:
        assert _parse_usdc_amount("0.01") == 10_000


class TestSignPaymentAuthorization:
    def test_returns_x402_payload_v2_format(self) -> None:
        auth = sign_payment_authorization(
            private_key=TEST_PRIVATE_KEY,
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            amount="1.00",
            token_address=USDC_ADDRESS,
            chain_id=CHAIN_ID,
            network="eip155:8453",
            accepted=MOCK_ACCEPTED,
        )

        # x402 PaymentPayload v2 envelope
        assert auth["x402Version"] == 2
        assert auth["accepted"]["scheme"] == "exact"
        assert auth["accepted"]["network"] == "eip155:8453"

        # Payload contains signature and authorization
        payload = auth["payload"]
        assert isinstance(payload["signature"], str)
        assert payload["signature"].startswith("0x")

        # Authorization fields
        authorization = payload["authorization"]
        assert authorization["from"] == TEST_ADDRESS
        assert authorization["to"] == TO_ADDRESS
        assert authorization["value"] == "1000000"
        assert isinstance(authorization["validAfter"], str)
        assert isinstance(authorization["validBefore"], str)
        assert int(authorization["validBefore"]) > int(authorization["validAfter"])
        assert authorization["nonce"].startswith("0x") and len(authorization["nonce"]) == 66

    def test_different_calls_produce_different_nonces(self) -> None:
        auth1 = sign_payment_authorization(
            private_key=TEST_PRIVATE_KEY,
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            amount="1.00",
            token_address=USDC_ADDRESS,
            chain_id=CHAIN_ID,
            network="eip155:8453",
            accepted=MOCK_ACCEPTED,
        )
        auth2 = sign_payment_authorization(
            private_key=TEST_PRIVATE_KEY,
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            amount="1.00",
            token_address=USDC_ADDRESS,
            chain_id=CHAIN_ID,
            network="eip155:8453",
            accepted=MOCK_ACCEPTED,
        )

        assert auth1["payload"]["authorization"]["nonce"] != auth2["payload"]["authorization"]["nonce"]


class TestBuildZeroCostAuthorization:
    def test_returns_valid_payload(self) -> None:
        auth = build_zero_cost_authorization(
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            accepted=MOCK_ACCEPTED,
        )
        assert auth["x402Version"] == 2
        assert auth["payload"]["signature"] == "0x"
        assert auth["payload"]["authorization"]["value"] == "0"

    def test_authorization_addresses(self) -> None:
        auth = build_zero_cost_authorization(
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            accepted=MOCK_ACCEPTED,
        )
        assert auth["payload"]["authorization"]["from"] == TEST_ADDRESS
        assert auth["payload"]["authorization"]["to"] == TO_ADDRESS

    def test_nonce_is_32_zero_bytes(self) -> None:
        auth = build_zero_cost_authorization(
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
        )
        nonce = auth["payload"]["authorization"]["nonce"]
        assert nonce == "0x" + "00" * 32
        assert len(nonce) == 66

    def test_includes_resource_when_provided(self) -> None:
        resource = {"url": "https://api.example.com/v1/tools/research"}
        auth = build_zero_cost_authorization(
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            resource=resource,
        )
        assert auth["resource"] == resource

    def test_omits_resource_when_not_provided(self) -> None:
        auth = build_zero_cost_authorization(
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
        )
        assert "resource" not in auth

    def test_base64_roundtrip_server_detection(self) -> None:
        """Encoded zero-cost auth should be detectable by server step 5c."""
        import base64, json
        auth = build_zero_cost_authorization(
            from_address=TEST_ADDRESS,
            to_address=TO_ADDRESS,
            accepted=MOCK_ACCEPTED,
        )
        encoded = encode_payment_header(auth)
        decoded = json.loads(base64.b64decode(encoded))
        assert decoded["payload"]["authorization"]["value"] == "0"
