package leigh.chain;

import io.reactivex.Flowable;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.http.HttpService;

import java.util.List;

/**
 * Implementation of a block scanner.
 *
 * @author Alex Leigh
 */
public class BlockScanner {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(BlockScanner.class);
    private final String rpcUrl;
    private final ReplayOption replay;
    private final BlockTranHandler handler;

    public BlockScanner(String rpcUrl, ReplayOption replay, BlockTranHandler handler) {
        this.rpcUrl = rpcUrl;
        this.replay = replay;
        this.handler = handler;
    }

    /**
     * BUGS: This method does not exit if the PAST is scanned.
     */
    public void scan() {
        Web3j web3j = Web3j.build(new HttpService(rpcUrl));

        // TODO: Will potential scientific notation from BigInteger cause problems here?
        Flowable<EthBlock> subscription = switch (replay) {
            case PAST -> web3j.replayPastBlocksFlowable(DefaultBlockParameterName.EARLIEST,
                    true);
            case FUTURE -> web3j.blockFlowable(true);
            case PAST_AND_FUTURE -> web3j.replayPastAndFutureBlocksFlowable(DefaultBlockParameterName.EARLIEST,
                    true);
            default -> throw new IllegalArgumentException("Unknown replay option");
        };

        subscription.blockingForEach(ethBlock -> {
            EthBlock.Block b = ethBlock.getBlock();

            if (!b.getTransactions().isEmpty()) {
                logger.info("Found non-empty block. [blockId: {}]", b.getNumber());

                List<EthBlock.TransactionResult> t = b.getTransactions();
                for (EthBlock.TransactionResult tr : t) {
                    handler.event(b, (EthBlock.TransactionObject) tr.get());
                }
            }
        });
    }
}
