# -*- coding: utf-8 -*-
import pytest
import ethereum.db
import ethereum.blocks
import ethereum.config
from ethereum import tester
from ethereum.utils import int_to_addr, zpad
from pyethapp.jsonrpc import address_decoder, data_decoder, quantity_decoder

from raiden.utils import privatekey_to_address
from raiden.tests.utils.blockchain import DEFAULT_BALANCE
from raiden.tests.utils.tester import (
    approve_and_deposit,
    channel_from_nettingcontract,
    create_registryproxy,
    create_tokenproxy,
    deploy_channelmanager_library,
    deploy_nettingchannel_library,
    deploy_registry,
    deploy_standard_token,
    new_channelmanager,
    new_nettingcontract,
)
from raiden.tests.utils.tester_client import ChannelExternalStateTester


@pytest.fixture
def tester_blockgas_limit():
    """ The tester's block gas limit.

    Set this value to `GAS_LIMIT`ing if the test needs to consider the gas usage.

    Note:
        `GAS_LIMIT` is defined in `raiden.network.rpc.client.GAS_LIMIT`
    """
    return 10 ** 10


@pytest.fixture
def tester_events():
    return list()


@pytest.fixture
def tester_state(deploy_key, private_keys, tester_blockgas_limit):
    tester_state = tester.state()

    # special addresses 1 to 5
    alloc = {
        int_to_addr(i): {'wei': 1}
        for i in range(1, 5)
    }

    for privkey in [deploy_key] + private_keys:
        address = privatekey_to_address(privkey)
        alloc[address] = {
            'balance': DEFAULT_BALANCE,
        }

    for account in tester.accounts:
        alloc[account] = {
            'balance': DEFAULT_BALANCE,
        }

    db = ethereum.db.EphemDB()
    env = ethereum.config.Env(
        db,
        ethereum.config.default_config,
    )
    genesis_overwrite = {
        'nonce': zpad(data_decoder('0x00006d6f7264656e'), 8),
        'difficulty': quantity_decoder('0x20000'),
        'mixhash': zpad(b'\x00', 32),
        'coinbase': address_decoder('0x0000000000000000000000000000000000000000'),
        'timestamp': 0,
        'extra_data': b'',
        'gas_limit': tester_blockgas_limit,
        'start_alloc': alloc,
    }
    genesis_block = ethereum.blocks.genesis(
        env,
        **genesis_overwrite
    )

    # enable DELEGATECALL opcode
    genesis_block.number = genesis_block.config['HOMESTEAD_FORK_BLKNUM'] + 1

    tester_state.db = db
    tester_state.env = env
    tester_state.block = genesis_block
    tester_state.block_gas_limit = tester_blockgas_limit
    tester_state.blocks = [genesis_block]

    return tester_state


@pytest.fixture
def tester_token_address(private_keys, token_amount, tester_state, sender_index=0):
    deploy_key = private_keys[sender_index]

    return deploy_standard_token(
        deploy_key,
        tester_state,
        token_amount,
    )


@pytest.fixture
def tester_nettingchannel_library_address(deploy_key, tester_state):
    return deploy_nettingchannel_library(
        deploy_key,
        tester_state,
    )


@pytest.fixture
def tester_channelmanager_library_address(
        deploy_key,
        tester_state,
        tester_nettingchannel_library_address):
    return deploy_channelmanager_library(
        deploy_key,
        tester_state,
        tester_nettingchannel_library_address,
    )


@pytest.fixture
def tester_registry_address(tester_state, deploy_key, tester_channelmanager_library_address):
    return deploy_registry(
        deploy_key,
        tester_state,
        tester_channelmanager_library_address,
    )


@pytest.fixture
def tester_token_raw(tester_state, tester_token_address, tester_events):
    return create_tokenproxy(
        tester_state,
        tester_token_address,
        tester_events.append,
    )


@pytest.fixture
def tester_token(token_amount, private_keys, tester_state, tester_token_address, tester_events):
    token = create_tokenproxy(
        tester_state,
        tester_token_address,
        tester_events.append,
    )

    privatekey0 = private_keys[0]
    for transfer_to in private_keys[1:]:
        token.transfer(  # pylint: disable=no-member