# standard imports
import logging

# external imports
from chainlib.eth.address import (
        to_checksum_address,
        )
from chainlib.eth.error import RequestMismatchException
from chainlib.status import Status
from cic_eth_registry.erc20 import ERC20Token
from cic_eth_registry.error import (
        NotAContractError,
        ContractMismatchError,
        )
from eth_erc20 import ERC20

# local imports
from .base import TagSyncFilter
from cic_cache import db as cic_cache_db

logg = logging.getLogger().getChild(__name__)


class ERC20TransferFilter(TagSyncFilter):

    def __init__(self, chain_spec):
        super(ERC20TransferFilter, self).__init__('transfer', domain='erc20')
        self.chain_spec = chain_spec


    # TODO: Verify token in declarator / token index
    def filter(self, conn, block, tx, db_session=None):
        logg.debug('filter {} {}'.format(block, tx))
        token = None
        try:
            token = ERC20Token(self.chain_spec, conn, tx.inputs[0])
        except NotAContractError:
            logg.debug('not a contract {}'.format(tx.inputs[0]))
            return False
        except ContractMismatchError:
            logg.debug('not an erc20 token  {}'.format(tx.inputs[0]))
            return False

        transfer_data = None
        try:
            transfer_data = ERC20.parse_transfer_request(tx.payload)
        except RequestMismatchException:
            logg.debug('erc20 match but not a transfer, skipping')
            return False
        except ValueError:
            logg.debug('erc20 match but bogus data, skipping')
            return False

        token_sender = tx.outputs[0]
        token_recipient = transfer_data[0]
        token_value = transfer_data[1]

        logg.debug('matched erc20 token transfer {} ({}) to {} value {}'.format(token.name, token.address, transfer_data[0], transfer_data[1]))

        cic_cache_db.add_transaction(
                db_session,
                tx.hash,
                block.number,
                tx.index,
                to_checksum_address(token_sender),
                to_checksum_address(token_recipient),
                token.address,
                token.address,
                token_value,
                token_value,
                tx.status == Status.SUCCESS,
                block.timestamp,
                )
        db_session.flush()
        cic_cache_db.tag_transaction(
                db_session,
                tx.hash,
                self.tag_name,
                domain=self.tag_domain,
                )
        db_session.commit()

        return True
