"""Tests for social-value types — immutability, validation, and secret handling."""

import pytest

from social_value.types import (
    BatchTransferItem,
    FeeEstimate,
    PaymentRecord,
    SecretStr,
    TransferResult,
    WalletState,
)


# ── SecretStr ────────────────────────────────────────────────


def test_secret_str_redacts_repr():
    s = SecretStr("my-secret-mnemonic")
    assert "my-secret" not in repr(s)
    assert "***" in repr(s)


def test_secret_str_redacts_str():
    s = SecretStr("my-secret-mnemonic")
    assert str(s) == "***"


def test_secret_str_get_value():
    s = SecretStr("my-secret-mnemonic")
    assert s.get_secret_value() == "my-secret-mnemonic"


def test_secret_str_bool():
    assert bool(SecretStr("notempty")) is True
    assert bool(SecretStr("")) is False


def test_secret_str_immutable():
    s = SecretStr("value")
    with pytest.raises(AttributeError):
        s._value = "changed"


def test_secret_str_not_in_format():
    s = SecretStr("my-secret")
    assert "my-secret" not in f"Config: {s}"
    assert "***" in f"Config: {s}"


# ── WalletState ──────────────────────────────────────────────


def test_wallet_state_available():
    state = WalletState(balance_sat=5000, pending_send_sat=1000)
    assert state.available_sat == 4000


def test_wallet_state_frozen():
    state = WalletState(balance_sat=5000)
    with pytest.raises(AttributeError):
        state.balance_sat = 9999


def test_wallet_state_defaults():
    state = WalletState(balance_sat=1000)
    assert state.pending_send_sat == 0
    assert state.pending_receive_sat == 0
    assert state.available_sat == 1000


# ── FeeEstimate ──────────────────────────────────────────────


def test_fee_estimate_total():
    est = FeeEstimate(action="deposit", amount_sat=5000, fee_sat=47, fee_pct=0.94)
    assert est.total_sat == 5047


def test_fee_estimate_frozen():
    est = FeeEstimate(action="deposit", amount_sat=5000, fee_sat=47, fee_pct=0.94)
    with pytest.raises(AttributeError):
        est.fee_sat = 0


# ── TransferResult ───────────────────────────────────────────


def test_transfer_result_fields():
    result = TransferResult(
        success=True,
        amount_sat=100,
        fee_sat=1,
        destination="lnbc1...",
        memo="test",
    )
    assert result.success is True
    assert result.amount_sat == 100
    assert result.timestamp > 0


def test_transfer_result_frozen():
    result = TransferResult(success=True, amount_sat=100, fee_sat=1, destination="x")
    with pytest.raises(AttributeError):
        result.success = False


# ── PaymentRecord ────────────────────────────────────────────


def test_payment_record_valid():
    record = PaymentRecord(
        payment_id="abc", direction="send", amount_sat=500, fee_sat=2, destination="lnbc..."
    )
    assert record.direction == "send"


def test_payment_record_invalid_direction():
    with pytest.raises(ValueError, match="direction must be"):
        PaymentRecord(
            payment_id="abc", direction="invalid", amount_sat=500, fee_sat=2, destination="x"
        )


def test_payment_record_negative_amount():
    with pytest.raises(ValueError, match="non-negative"):
        PaymentRecord(
            payment_id="abc", direction="send", amount_sat=-1, fee_sat=0, destination="x"
        )


# ── BatchTransferItem ────────────────────────────────────────


def test_batch_item_valid():
    item = BatchTransferItem(destination="addr123", amount_sat=100, memo="test")
    assert item.amount_sat == 100


def test_batch_item_zero_amount():
    with pytest.raises(ValueError, match="positive"):
        BatchTransferItem(destination="addr123", amount_sat=0)


def test_batch_item_negative_amount():
    with pytest.raises(ValueError, match="positive"):
        BatchTransferItem(destination="addr123", amount_sat=-100)


def test_batch_item_long_memo():
    with pytest.raises(ValueError, match="280 chars"):
        BatchTransferItem(destination="addr123", amount_sat=100, memo="x" * 281)


def test_batch_item_empty_destination():
    with pytest.raises(ValueError, match="non-empty"):
        BatchTransferItem(destination="", amount_sat=100)


def test_batch_item_whitespace_destination():
    with pytest.raises(ValueError, match="non-empty"):
        BatchTransferItem(destination="   ", amount_sat=100)
