"""
Shared test fixtures for the BAL plugin test-suite.

This module centralises the "plausible data" used by the mock tests:

    * Valid Bitcoin (regtest) addresses are read **read-only** from the
      ``giovanna7`` wallet so the heirs / change / will-executor addresses are
      genuine, well-formed addresses for the active network.
    * A lightweight fake wallet and a fake ``bal_plugin`` are provided so the
      core inheritance logic (``Heirs.buildTransactions`` / ``get_transactions``)
      can be exercised without a running Electrum daemon or any network access.

Nothing here touches the real wallet file other than reading it; the file is
opened read-only and never written back.
"""

import json
import os
from unittest.mock import MagicMock

from electrum.transaction import PartialTxInput, TxOutpoint
from electrum.util import bfh

# Read-only path to the giovanna7 regtest wallet used to source valid addresses.
GIOVANNA7_WALLET = (
    "/home/steal/devel/bal/electrum2/.electrum2222/regtest/wallets.old/giovanna7"
)

# Fallback regtest addresses (used if the wallet file is not available, e.g. on
# CI), so the address-dependent tests can still run.  These are valid regtest
# bech32 addresses taken from the giovanna7 wallet.
_FALLBACK_RECEIVING = [
    "bcrt1qpm5utekdtmzwnlkh7jq5497vwwf6sm38tljan5",
    "bcrt1qazle627r46apscly8lj4q5cxfxgrtuew879jde",
    "bcrt1qh2c83yulvs7kgw0g6q3lkxqws4cnf0uxpcgcpt",
    "bcrt1qsprcgaldcn6v6l6jw0w6annv7hgkpw7ycxu6mu",
    "bcrt1qy02pnw9lulnnwg6m77yghn6v7ndgnjph3hrdmy",
    "bcrt1qrmjaxllejgqu6azftsfu2cdjyrz8wjxzsv7wvp",
]
_FALLBACK_CHANGE = [
    "bcrt1qzu5u0fgpxq5v42r62aefc2xjn6mehgzhtj4pld",
    "bcrt1qs9ya5hserz44elcpt992r0ycrmh3w3chzffawc",
    "bcrt1q28qtj5ugfcm4psqenq54sh55uryealeeprk6ju",
]


def load_addresses():
    """Return ``(receiving, change)`` address lists from the giovanna7 wallet.

    Falls back to a small hard-coded set of valid regtest addresses when the
    wallet file cannot be read, so the tests remain runnable everywhere.
    """
    try:
        with open(GIOVANNA7_WALLET, "r") as f:
            data = json.load(f)
        receiving = data["addresses"]["receiving"]
        change = data["addresses"]["change"]
        if receiving and change:
            return receiving, change
    except Exception:
        pass
    return list(_FALLBACK_RECEIVING), list(_FALLBACK_CHANGE)


# Module-level cached address pools.
RECEIVING_ADDRESSES, CHANGE_ADDRESSES = load_addresses()


def heir_addresses(n):
    """Return ``n`` distinct valid heir addresses from the giovanna7 wallet."""
    # Use addresses further into the list so they do not collide with the
    # change address used by the fake wallet.
    return RECEIVING_ADDRESSES[10 : 10 + n]


def willexecutor_addresses(n):
    """Return ``n`` distinct valid will-executor payout addresses."""
    return RECEIVING_ADDRESSES[100 : 100 + n]


def change_address():
    """Return a single valid change address."""
    return CHANGE_ADDRESSES[0]


def make_utxo(txid_hex, value, out_idx=0):
    """Build a minimal spendable ``PartialTxInput`` with the given value.

    Only the fields required by the inheritance transaction builder are set
    (trusted value + ``is_mine``); this mirrors how Electrum hands UTXOs to the
    plugin without needing a real wallet.
    """
    txin = PartialTxInput(prevout=TxOutpoint(txid=bfh(txid_hex), out_idx=out_idx))
    txin._trusted_value_sats = value
    txin._TxInput__value_sats = value
    txin.is_mine = True
    return txin


def make_utxos(n, value=1_000_000, prefix="a1"):
    """Return ``n`` synthetic UTXOs of ``value`` satoshis each."""
    return [make_utxo(f"{prefix}{i:062x}", value) for i in range(n)]


def fake_wallet(dust_threshold=546):
    """Return a MagicMock wallet sufficient for the inheritance builder.

    The change address comes from the real giovanna7 wallet so generated
    transactions carry a valid change output address.
    """
    w = MagicMock()
    w.dust_threshold.return_value = dust_threshold
    w.get_change_addresses_for_new_transaction.return_value = [change_address()]
    w.get_utxos.return_value = []
    w.db.get.return_value = {}
    w.db.get_transaction.return_value = None
    return w


def fake_bal_plugin(willexecutors=None, no_willexecutor=False, decimal_point=8):
    """Return a fake ``bal_plugin`` exposing only what the builder reads.

    Args:
        willexecutors: ``{url: we_dict}`` mapping returned by
            ``Willexecutors.get_willexecutors`` (patched in the tests).
        no_willexecutor: value of the ``NO_WILLEXECUTOR`` toggle (whether a
            local backup transaction without will-executor is also produced).
        decimal_point: BTC decimal point (8 for satoshi precision).
    """
    plugin = MagicMock()
    plugin.get_decimal_point.return_value = decimal_point
    plugin.NO_WILLEXECUTOR.get.return_value = no_willexecutor
    plugin._willexecutors = willexecutors or {}
    return plugin
