"""
Unit tests for services/explorer_service.py: verify each network's response
is parsed into the normalized result shape, using synthetic API payloads
shaped like the real APIs (Moralis / Etherscan v2 / mempool.space / Solana
RPC / Tronscan).
"""

import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from financegpt_bot.services import explorer_service as es  # noqa: E402


class FakeResponse:
    def __init__(self, payload):
        self._payload = payload

    def raise_for_status(self):
        pass

    def json(self):
        return self._payload


def _erc20_transfer_input(destination_address: str, amount_raw: int) -> str:
    dest_hex = destination_address[2:].lower().rjust(64, "0")
    amount_hex = format(amount_raw, "x").rjust(64, "0")
    return "0xa9059cbb" + dest_hex + amount_hex


def test_bep20_erc20_style_token_transfer(monkeypatch):
    dest = "0x" + "ab".rjust(40, "0")
    amount_raw = 5 * 10 ** 18  # 5 tokens at 18 decimals
    tx = {
        "hash": "0xbep20hash",
        "from_address": "0x1111111111111111111111111111111111111a",
        "to_address": "0x55d398326f99059ff775485246999027b3197955",  # USDT (BEP20) contract
        "input": _erc20_transfer_input(dest, amount_raw),
        "value": "0",
        "receipt_status": "1",
        "block_timestamp": "2024-01-01T12:00:00.000Z",
        "logs": [],
    }
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse(tx))

    result = es.fetch_transaction("BEP20", "0xbep20hash")

    assert result["asset"] == "USDT"
    assert result["amount"] == "5.000000"
    assert result["destination_address"] == dest
    assert result["source_address"] == tx["from_address"]
    assert result["status"] == "تایید شده"
    assert result["network"] == "BEP-20"
    assert result["source"] == "https://bscscan.com/tx/0xbep20hash"
    assert result["date"].startswith("140")  # a Jalali year


def test_bep20_not_found(monkeypatch):
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse({}))
    try:
        es.fetch_transaction("BEP20", "0xmissing")
        assert False, "expected TransactionNotFound"
    except es.TransactionNotFound:
        pass


def test_erc20_token_transfer(monkeypatch):
    dest = "0x" + "cd".rjust(40, "0")
    amount_raw = 10 ** 6  # 1 USDT at 6 decimals
    tx = {
        "hash": "0xerc20hash",
        "from": "0x2222222222222222222222222222222222222b",
        "to": "0xdac17f958d2ee523a2206206994597c13d831ec7",  # USDT (Ethereum) contract
        "input": _erc20_transfer_input(dest, amount_raw),
        "value": "0x0",
        "blockTimestamp": hex(1700000000),
    }
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse({"result": tx}))

    result = es.fetch_transaction("ERC20", "0xerc20hash")

    assert result["asset"] == "USDT"
    assert float(result["amount"]) == 1.0
    assert result["destination_address"] == dest
    assert result["network"] == "ERC-20"
    assert result["source"] == "https://etherscan.io/tx/0xerc20hash"


def test_erc20_not_found(monkeypatch):
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse({"result": None}))
    try:
        es.fetch_transaction("ERC20", "0xmissing")
        assert False, "expected TransactionNotFound"
    except es.TransactionNotFound:
        pass


def test_btc_transaction(monkeypatch):
    tx = {
        "txid": "btchash",
        "status": {"confirmed": True, "block_time": 1700000000},
        "vin": [{"prevout": {"scriptpubkey_address": "bc1qsource"}}],
        "vout": [{"scriptpubkey_address": "bc1qdest", "value": 150000}],
    }
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse(tx))

    result = es.fetch_transaction("BTC", "btchash")

    assert result["source_address"] == "bc1qsource"
    assert result["destination_address"] == "bc1qdest"
    assert result["amount"] == "0.00150000"
    assert result["status"] == "تایید شده"
    assert result["network"] == "BTC"
    assert result["source"] == "https://mempool.space/tx/btchash"


def test_btc_unconfirmed(monkeypatch):
    tx = {
        "txid": "btchash2",
        "status": {"confirmed": False},
        "vin": [{"prevout": {"scriptpubkey_address": "bc1qsource"}}],
        "vout": [{"scriptpubkey_address": "bc1qdest", "value": 1000}],
    }
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse(tx))

    result = es.fetch_transaction("BTC", "btchash2")
    assert result["status"] == "در انتظار تایید شبکه"


def test_btc_not_found(monkeypatch):
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse({}))
    try:
        es.fetch_transaction("BTC", "missing")
        assert False, "expected TransactionNotFound"
    except es.TransactionNotFound:
        pass


def test_sol_transfer(monkeypatch):
    rpc_response = {
        "jsonrpc": "2.0",
        "id": 1,
        "result": {
            "blockTime": 1700000000,
            "meta": {"err": None},
            "transaction": {
                "signatures": ["solsig"],
                "message": {
                    "instructions": [
                        {
                            "program": "system",
                            "parsed": {
                                "type": "transfer",
                                "info": {"source": "SOLSRC", "destination": "SOLDST", "lamports": 500000000},
                            },
                        }
                    ],
                    "accountKeys": [{"pubkey": "SOLSRC", "signer": True}],
                },
            },
        },
    }
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse(rpc_response))

    result = es.fetch_transaction("SOL", "solhash")

    assert result["source_address"] == "SOLSRC"
    assert result["destination_address"] == "SOLDST"
    assert result["amount"] == "0.500000000"
    assert result["status"] == "تایید شده"
    assert result["source"] == "https://solscan.io/tx/solsig"


def test_sol_not_found(monkeypatch):
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse({"result": None}))
    try:
        es.fetch_transaction("SOL", "missing")
        assert False, "expected TransactionNotFound"
    except es.TransactionNotFound:
        pass


def test_trc20_single_transfer(monkeypatch):
    tx = {
        "hash": "trxhash",
        "Status": "SUCCESS",
        "transfersAllList": [
            {
                "from_address": "TFROM",
                "to_address": "TTO",
                "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
                "amount_str": "2000000",
                "decimals": 6,
                "symbol": "USDT",
            }
        ],
    }
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse(tx))

    result = es.fetch_transaction("TRC20", "trxhash")

    assert isinstance(result, list) and len(result) == 1
    assert result[0]["asset"] == "USDT"
    assert result[0]["amount"] == "2.000000"
    assert result[0]["source_address"] == "TFROM"
    assert result[0]["destination_address"] == "TTO"
    assert result[0]["network"] == "TRC-20"


def test_trc20_not_found(monkeypatch):
    monkeypatch.setattr(es.requests, "request", lambda *a, **k: FakeResponse({}))
    try:
        es.fetch_transaction("TRC20", "missing")
        assert False, "expected TransactionNotFound"
    except es.TransactionNotFound:
        pass
