import base64
import json

import pytest

from skytale_sdk.payment import (
    PaymentConfig,
    PaymentLimitExceeded,
    PaymentRequired,
    parse_payment_required,
)


class TestPaymentConfig:
    def test_strips_0x_prefix(self):
        cfg = PaymentConfig(wallet_key="0xabcdef1234", network="base-sepolia")
        assert cfg.wallet_key == "abcdef1234"

    def test_strips_0X_prefix(self):
        cfg = PaymentConfig(wallet_key="0Xabcdef1234")
        assert cfg.wallet_key == "abcdef1234"

    def test_no_prefix_unchanged(self):
        cfg = PaymentConfig(wallet_key="abcdef1234")
        assert cfg.wallet_key == "abcdef1234"

    def test_defaults(self):
        cfg = PaymentConfig(wallet_key="abc")
        assert cfg.network == "base-sepolia"
        assert cfg.max_per_message == "0.01"
        assert cfg.auto_pay is True


class TestMaxPerMessageMinor:
    def test_whole_number(self):
        cfg = PaymentConfig(wallet_key="abc", max_per_message="1")
        assert cfg.max_per_message_minor == 1_000_000

    def test_decimal(self):
        cfg = PaymentConfig(wallet_key="abc", max_per_message="0.01")
        assert cfg.max_per_message_minor == 10_000

    def test_six_decimals(self):
        cfg = PaymentConfig(wallet_key="abc", max_per_message="0.123456")
        assert cfg.max_per_message_minor == 123_456

    def test_more_than_six_decimals_truncated(self):
        cfg = PaymentConfig(wallet_key="abc", max_per_message="0.1234569999")
        assert cfg.max_per_message_minor == 123_456

    def test_fewer_decimals_padded(self):
        cfg = PaymentConfig(wallet_key="abc", max_per_message="0.1")
        assert cfg.max_per_message_minor == 100_000

    def test_large_amount(self):
        cfg = PaymentConfig(wallet_key="abc", max_per_message="100.50")
        assert cfg.max_per_message_minor == 100_500_000


class TestParsePaymentRequired:
    def test_parses_base64_json(self):
        requirement = {
            "scheme": "exact",
            "network": "base-sepolia",
            "maxAmountRequired": 10000,
            "asset": "0xUSDC",
            "payTo": "0xRecipient",
        }
        encoded = base64.b64encode(json.dumps(requirement).encode()).decode()
        result = parse_payment_required(encoded)
        assert result["scheme"] == "exact"
        assert result["maxAmountRequired"] == 10000
        assert result["network"] == "base-sepolia"
        assert result["asset"] == "0xUSDC"
        assert result["payTo"] == "0xRecipient"

    def test_invalid_base64_raises(self):
        with pytest.raises(Exception):
            parse_payment_required("not-valid-base64!!!")


class TestPaymentRequired:
    def test_attributes(self):
        raw = {
            "maxAmountRequired": 5000,
            "network": "base-sepolia",
            "asset": "0xUSDC",
            "payTo": "0xRecipient",
        }
        exc = PaymentRequired(raw)
        assert exc.amount == 5000
        assert exc.network == "base-sepolia"
        assert exc.token == "0xUSDC"
        assert exc.recipient == "0xRecipient"
        assert exc.raw is raw

    def test_message(self):
        exc = PaymentRequired({
            "maxAmountRequired": 100,
            "network": "ethereum-mainnet",
            "payTo": "0xAddr",
        })
        assert "100" in str(exc)
        assert "ethereum-mainnet" in str(exc)

    def test_missing_fields_default(self):
        exc = PaymentRequired({})
        assert exc.amount == 0
        assert exc.network == ""
        assert exc.token == ""
        assert exc.recipient == ""


class TestPaymentLimitExceeded:
    def test_attributes(self):
        exc = PaymentLimitExceeded(50000, 10000)
        assert exc.requested == 50000
        assert exc.limit == 10000

    def test_message(self):
        exc = PaymentLimitExceeded(50000, 10000)
        assert "50000" in str(exc)
        assert "10000" in str(exc)

    def test_is_exception(self):
        with pytest.raises(PaymentLimitExceeded):
            raise PaymentLimitExceeded(100, 50)
