import os
import sys
import time
from pathlib import Path

import pytest

SDK_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(SDK_ROOT / "paegents"))

ESCROW_CONTRACT = "0xcA98356B65951b621C32B840F0266847C6043B45"
BASE_SEPOLIA_USDC_DOMAIN_SEPARATOR = "71f17a3b2ff373b803d70a5a07c046c1a2bc8e89c09ef722fcb047abe94c9818"

from escrow_signing import (  # noqa: E402
    CHAIN_CONFIG,
    _build_domain_separator,
    build_bilateral_agreement_signatures,
    sign_buyer_withdraw_intent,
    sign_deposit_authorization,
    sign_initiate_close_intent,
    sign_seller_claim_intent,
    validate_amount,
    verify_calldata_selector,
)


def future_deadline(seconds: int = 600) -> int:
    return int(time.time()) + seconds


def test_validate_amount_mismatch_raises():
    with pytest.raises(ValueError, match="Amount mismatch"):
        validate_amount(
            {"service_amount_atomic": 1},
            quantity=100,
            price_per_unit_cents=10,
        )


def test_verify_calldata_selector_recognizes_known_selector():
    fn_name = verify_calldata_selector("0x379607f500000000")
    assert fn_name == "sellerClaim(uint256)"


def test_build_signatures_enforces_amount_validation_before_signing():
    deadline = future_deadline()
    with pytest.raises(ValueError, match="Amount mismatch"):
        build_bilateral_agreement_signatures(
            buyer_private_key="0x" + "11" * 32,
            deposit_params={
                "agreement_id": "agr_1",
                "chain_id": 84532,
                "usdc_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
                "escrow_contract_address": ESCROW_CONTRACT,
                "service_amount_atomic": 1,
            },
            quantity=100,
            price_per_unit_cents=10,
            permit_deadline=deadline,
            usdc_permit_nonce=0,
        )


def test_build_signatures_initial_flow_omits_deposit_auth_without_onchain_id():
    deadline = future_deadline()
    result = build_bilateral_agreement_signatures(
        buyer_private_key="0x" + "11" * 32,
        deposit_params={
            "agreement_id": "agr_1",
            "chain_id": 84532,
            "usdc_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
            "escrow_contract_address": ESCROW_CONTRACT,
            "service_amount_atomic": 10_000_000,
        },
        quantity=100,
        price_per_unit_cents=10,
        permit_deadline=deadline,
        usdc_permit_nonce=0,
    )

    assert result["buyer_permit_signature"].startswith("0x")
    assert "buyer_deposit_auth_signature" not in result


def test_build_signatures_uses_onchain_agreement_id_for_deposit_auth():
    private_key = "0x" + "11" * 32
    deadline = future_deadline()
    deposit_params = {
        "agreement_id": "agr_1",
        "chain_id": 84532,
        "usdc_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
        "escrow_contract_address": ESCROW_CONTRACT,
        "service_amount_atomic": 10_000_000,
        "onchain_agreement_id": 7,
    }

    result = build_bilateral_agreement_signatures(
        buyer_private_key=private_key,
        deposit_params=deposit_params,
        quantity=100,
        price_per_unit_cents=10,
        deposit_auth_deadline=deadline,
    )

    expected = sign_deposit_authorization(
        buyer_private_key=private_key,
        agreement_id=7,
        deadline=deadline,
        chain_id=84532,
        escrow_contract_address=ESCROW_CONTRACT,
    )

    assert result["buyer_deposit_auth_signature"] == expected["signature"]
    assert "buyer_permit_signature" not in result


def test_base_sepolia_usdc_domain_matches_live_token():
    assert CHAIN_CONFIG[84532]["usdc_name"] == "USDC"
    domain_separator = _build_domain_separator(
        CHAIN_CONFIG[84532]["usdc_name"],
        CHAIN_CONFIG[84532]["usdc_version"],
        84532,
        CHAIN_CONFIG[84532]["usdc_address"],
    )
    assert domain_separator.hex() == BASE_SEPOLIA_USDC_DOMAIN_SEPARATOR


def test_build_signatures_requires_permit_nonce_or_onchain_agreement_id():
    with pytest.raises(
        ValueError,
        match="Either usdc_permit_nonce or deposit_params.onchain_agreement_id is required",
    ):
        build_bilateral_agreement_signatures(
            buyer_private_key="0x" + "11" * 32,
            deposit_params={
                "agreement_id": "agr_1",
                "chain_id": 84532,
                "usdc_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
                "escrow_contract_address": ESCROW_CONTRACT,
                "service_amount_atomic": 10_000_000,
            },
            quantity=100,
            price_per_unit_cents=10,
        )


def test_build_signatures_requires_deposit_auth_deadline_when_onchain_id_present():
    with pytest.raises(
        ValueError,
        match="deposit_auth_deadline is required when onchain_agreement_id is present",
    ):
        build_bilateral_agreement_signatures(
            buyer_private_key="0x" + "11" * 32,
            deposit_params={
                "agreement_id": "agr_1",
                "chain_id": 84532,
                "usdc_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
                "escrow_contract_address": ESCROW_CONTRACT,
                "service_amount_atomic": 10_000_000,
                "onchain_agreement_id": 7,
            },
            quantity=100,
            price_per_unit_cents=10,
        )


def test_sign_initiate_close_intent_includes_nonce_and_deadline():
    deadline = future_deadline()
    result = sign_initiate_close_intent(
        signer_private_key="0x" + "22" * 32,
        agreement_id=7,
        nonce=3,
        deadline=deadline,
        chain_id=84532,
        escrow_contract_address=ESCROW_CONTRACT,
    )

    assert result["signature"].startswith("0x")
    assert result["nonce"] == 3
    assert result["deadline"] == deadline


def test_sponsored_action_signatures_are_distinct_per_action():
    deadline = future_deadline()
    kwargs = {
        "signer_private_key": "0x" + "33" * 32,
        "agreement_id": 7,
        "nonce": 0,
        "deadline": deadline,
        "chain_id": 84532,
        "escrow_contract_address": ESCROW_CONTRACT,
    }

    close_sig = sign_initiate_close_intent(**kwargs)["signature"]
    seller_sig = sign_seller_claim_intent(**kwargs)["signature"]
    buyer_sig = sign_buyer_withdraw_intent(**kwargs)["signature"]

    assert close_sig != seller_sig
    assert close_sig != buyer_sig
    assert seller_sig != buyer_sig
