"""Tests for on-chain escrow helpers."""

import pytest

from swarmpay.onchain_escrow import (
    OnchainEscrowClient,
    OnchainEscrowConfig,
    OnchainEscrowFundingResult,
    OnchainEscrowIntent,
    OnchainEscrowStatus,
    build_escrow_id,
    create_onchain_record,
    hash_escrow_metadata,
)
from swarmpay.wallet import AgentWallet


class MockProvider:
    def __init__(self):
        self.address = "0x1111111111111111111111111111111111111111"
        self.calls = []

    def send_transaction(self, tx):
        self.calls.append(tx)
        return f"0xTX{len(self.calls)}"


def test_build_escrow_id_normalizes_contract_address():
    escrow_id = build_escrow_id(84532, "0xABCDEF1234567890ABCDEF1234567890ABCDEF12", 7)
    assert escrow_id == "escrow:84532:0xabcdef1234567890abcdef1234567890abcdef12:7"


def test_hash_escrow_metadata_is_stable():
    first = hash_escrow_metadata("translation", "job-42", "salt")
    second = hash_escrow_metadata("translation", "job-42", "salt")
    assert first == second
    assert first.startswith("0x")
    assert len(first) == 66


def test_intent_validate_rejects_amount_mismatch():
    intent = OnchainEscrowIntent(
        buyer_wallet="0x1111111111111111111111111111111111111111",
        provider_wallet="0x2222222222222222222222222222222222222222",
        token_address="0x3333333333333333333333333333333333333333",
        total_amount_atomic=100,
        provider_amount_atomic=90,
        fee_amount_atomic=5,
        deadline_unix=1_800_000_000,
        metadata_hash=hash_escrow_metadata("translation"),
    )

    with pytest.raises(ValueError):
        intent.validate()


def test_create_onchain_record():
    config = OnchainEscrowConfig(
        chain_id=84532,
        contract_address="0xABCDEF1234567890ABCDEF1234567890ABCDEF12",
        token_address="0x3333333333333333333333333333333333333333",
        fee_recipient="0x4444444444444444444444444444444444444444",
        dispute_resolver="0x5555555555555555555555555555555555555555",
    )
    intent = OnchainEscrowIntent(
        buyer_wallet="0x1111111111111111111111111111111111111111",
        provider_wallet="0x2222222222222222222222222222222222222222",
        token_address=config.token_address,
        total_amount_atomic=100,
        provider_amount_atomic=99,
        fee_amount_atomic=1,
        deadline_unix=1_800_000_000,
        metadata_hash=hash_escrow_metadata("translation", "job-42"),
    )

    record = create_onchain_record(config, 3, intent, tx_hash="0xTX")

    assert record.escrow_id == "escrow:84532:0xabcdef1234567890abcdef1234567890abcdef12:3"
    assert record.status == OnchainEscrowStatus.FUNDED
    assert record.tx_hash == "0xTX"


def test_build_fund_tx_contains_selector_and_target():
    config = OnchainEscrowConfig(
        chain_id=84532,
        contract_address="0xABCDEF1234567890ABCDEF1234567890ABCDEF12",
        token_address="0x3333333333333333333333333333333333333333",
        fee_recipient="0x4444444444444444444444444444444444444444",
        dispute_resolver="0x5555555555555555555555555555555555555555",
    )
    client = OnchainEscrowClient(config)
    intent = OnchainEscrowIntent(
        buyer_wallet="0x1111111111111111111111111111111111111111",
        provider_wallet="0x2222222222222222222222222222222222222222",
        token_address=config.token_address,
        total_amount_atomic=100,
        provider_amount_atomic=99,
        fee_amount_atomic=1,
        deadline_unix=1_800_000_000,
        metadata_hash=hash_escrow_metadata("translation", "job-42"),
    )

    tx = client.build_fund_tx(intent)

    assert tx.to == config.contract_address
    assert tx.data.startswith("0xee5e8f20")


def test_fund_with_wallet_sends_approve_then_fund():
    config = OnchainEscrowConfig(
        chain_id=84532,
        contract_address="0xABCDEF1234567890ABCDEF1234567890ABCDEF12",
        token_address="0x3333333333333333333333333333333333333333",
        fee_recipient="0x4444444444444444444444444444444444444444",
        dispute_resolver="0x5555555555555555555555555555555555555555",
    )
    client = OnchainEscrowClient(config)
    provider = MockProvider()
    wallet = AgentWallet(agent_id="buyer", wallet_provider=provider)
    intent = OnchainEscrowIntent(
        buyer_wallet=provider.address,
        provider_wallet="0x2222222222222222222222222222222222222222",
        token_address=config.token_address,
        total_amount_atomic=100,
        provider_amount_atomic=99,
        fee_amount_atomic=1,
        deadline_unix=1_800_000_000,
        metadata_hash=hash_escrow_metadata("translation", "job-42"),
    )

    result = client.fund_with_wallet(wallet, 4, intent)

    assert isinstance(result, OnchainEscrowFundingResult)
    assert result.approval_tx_hash == "0xTX1"
    assert result.funding_tx_hash == "0xTX2"
    assert result.expected_escrow_id.endswith(":4")
    assert provider.calls[0]["to"] == config.token_address
    assert provider.calls[1]["to"] == config.contract_address


def test_build_dispute_tx_contains_reason_hash():
    config = OnchainEscrowConfig(
        chain_id=84532,
        contract_address="0xABCDEF1234567890ABCDEF1234567890ABCDEF12",
        token_address="0x3333333333333333333333333333333333333333",
        fee_recipient="0x4444444444444444444444444444444444444444",
        dispute_resolver="0x5555555555555555555555555555555555555555",
    )
    client = OnchainEscrowClient(config)
    reason_hash = hash_escrow_metadata("dispute", "bad-quality")

    tx = client.build_dispute_tx(7, reason_hash)

    assert tx.to == config.contract_address
    assert tx.data.startswith("0xc1e6a198")
    assert reason_hash[2:] in tx.data
