#!/usr/bin/env python3

import decimal
import mock
import wallycore as wally

import garecovery.two_of_three
from garecovery.clargs import DEFAULT_SUBACCOUNT_SEARCH_DEPTH
from gaservices.utils import txutil
from .util import AuthServiceProxy, datafile, get_output, parse_summary, raise_IOError


garecovery.bitcoin_config.open = raise_IOError
sub_depth = DEFAULT_SUBACCOUNT_SEARCH_DEPTH
key_depth = 20
destination_address = 'mynHfTyTWyGGB76NBFbfUrTnn8YWQkTJVs'


@mock.patch('garecovery.two_of_three.bitcoincore.AuthServiceProxy')
def test_recover_2of3(mock_bitcoincore):
    """Test 2of3 happy path"""
    mock_bitcoincore.return_value = AuthServiceProxy('testnet_txs')

    estimate = {'blocks': 3, 'feerate': 1, }
    mock_bitcoincore.return_value.estimatesmartfee.return_value = estimate

    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_6.txt')),
        '--rpcuser=abc',
        '--rpcpassword=<PASSWORD>',
        '2of3',
        '--network=testnet',
        '--recovery-mnemonic-file={}'.format(datafile('mnemonic_7.txt')),
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
        '--destination-address={}'.format(destination_address),
    ]

    # Raw tx
    output = get_output(args).strip()
    assert output == open(datafile("signed_2of3_5")).read().strip()

    # Check replace by fee is set
    tx = txutil.from_hex(output)
    assert wally.tx_get_num_inputs(tx) == 1
    assert wally.tx_get_input_sequence(tx, 0) == int(32*'1', 2) - 2

    # Summary
    args = ['--show-summary', ] + args
    output = get_output(args)
    summary = parse_summary(output)
    assert len(summary) == 1
    assert summary[0]['destination address'] == destination_address


@mock.patch('garecovery.two_of_three.bitcoincore.AuthServiceProxy')
def test_set_nlocktime(mock_bitcoincore):
    """Test that newly created recovery transactions have nlocktime = current blockheight + 1"""
    mock_bitcoincore.return_value = AuthServiceProxy('testnet_txs')
    estimate = {'blocks': 3, 'feerate': 1, }
    mock_bitcoincore.return_value.estimatesmartfee.return_value = estimate

    current_blockheight = 123
    mock_bitcoincore.return_value.getblockcount.return_value = current_blockheight

    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_6.txt')),
        '--rpcuser=abc',
        '--rpcpassword=<PASSWORD>',
        '2of3',
        '--network=testnet',
        '--recovery-mnemonic-file={}'.format(datafile('mnemonic_7.txt')),
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
        '--destination-address={}'.format(destination_address),
    ]

    output = get_output(args).strip()
    tx = txutil.from_hex(output)
    assert wally.tx_get_locktime(tx) == current_blockheight


@mock.patch('garecovery.two_of_three.bitcoincore.AuthServiceProxy')
def test_recover_2of2_csv(mock_bitcoincore):
    """Test 2of2-csv happy path"""
    mock_bitcoincore.return_value = AuthServiceProxy('testnet_txs')

    estimate = {'blocks': 3, 'feerate': decimal.Decimal('0.00001'), }
    mock_bitcoincore.return_value.estimatesmartfee.return_value = estimate
    mock_bitcoincore.return_value.getnetworkinfo = mock.Mock(return_value={'version': 190100})
    mock_bitcoincore.return_value.getblockcount.return_value = 144

    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_1.txt')),
        '--rpcuser=abc',
        '--rpcpassword=<PASSWORD>',
        '2of2-csv',
        '--network=testnet',
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
    ]

    # Raw tx
    output = get_output(args).strip()
    assert output == open(datafile("signed_2of2_csv_1")).read().strip()

    tx = txutil.from_hex(output)
    assert wally.tx_get_num_inputs(tx) == 1

    # Summary
    args = ['--show-summary', ] + args
    output = get_output(args)
    summary = parse_summary(output)
    assert len(summary) == 1

    # Use scantxoutset instead of importmulti + listunspent
    scantxoutset_result = {
        'success': True,
        'unspents': [{
            'txid': '0ab5d70ef25a601de455155fdcb8c492d21a9b3063211dc8a969568d9d0fe15b',
            'vout': 0,
            'scriptPubKey': 'a91458ce12e1773dd078940a9dc855b94c3c9a343b8587',
            'desc': 'addr(2N1LnKRLTCWr8H9UdwoREazuFDXHMEgZj9g)#ztm9gzsm',
            'amount': 0.001,
            'height': 0,
        }],
    }
    mock_bitcoincore.return_value.scantxoutset = mock.Mock(return_value=scantxoutset_result)
    # output not expired yet
    mock_bitcoincore.return_value.getblockcount.return_value = 143

    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_1.txt')),
        '--rpcuser=abc',
        '--rpcpassword=<PASSWORD>',
        '2of2-csv',
        '--network=testnet',
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
        '--ignore-mempool',
    ]

    # Raw tx
    raw_tx = get_output(args).strip()
    assert raw_tx == ''

    # output expired
    mock_bitcoincore.return_value.getblockcount.return_value = 144

    # Raw tx
    output = get_output(args).strip()
    assert output == open(datafile("signed_2of2_csv_1")).read().strip()

    # Check replace by fee is set
    tx = txutil.from_hex(output)
    assert wally.tx_get_num_inputs(tx) == 1

    # Summary
    args = ['--show-summary', ] + args
    output = get_output(args)
    summary = parse_summary(output)
    assert len(summary) == 1
