using System.Numerics;
using Managing.Tools.ABI.OrderBookReader.ContractDefinition;
using Nethereum.Contracts.ContractHandlers;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Web3;

namespace Managing.Tools.ABI.OrderBookReader
{
    public class OrderBookReaderService
    {
        public static Task<TransactionReceipt> DeployContractAndWaitForReceiptAsync(Web3 web3,
            OrderBookReaderDeployment orderBookReaderDeployment, CancellationTokenSource cancellationTokenSource = null)
        {
            return web3.Eth.GetContractDeploymentHandler<OrderBookReaderDeployment>()
                .SendRequestAndWaitForReceiptAsync(orderBookReaderDeployment, cancellationTokenSource);
        }

        public static Task<string> DeployContractAsync(Web3 web3, OrderBookReaderDeployment orderBookReaderDeployment)
        {
            return web3.Eth.GetContractDeploymentHandler<OrderBookReaderDeployment>()
                .SendRequestAsync(orderBookReaderDeployment);
        }

        public static async Task<OrderBookReaderService> DeployContractAndGetServiceAsync(Web3 web3,
            OrderBookReaderDeployment orderBookReaderDeployment, CancellationTokenSource cancellationTokenSource = null)
        {
            var receipt =
                await DeployContractAndWaitForReceiptAsync(web3, orderBookReaderDeployment, cancellationTokenSource);
            return new OrderBookReaderService(web3, receipt.ContractAddress);
        }

        protected IWeb3 Web3 { get; }

        public ContractHandler ContractHandler { get; }

        public OrderBookReaderService(Web3 web3, string contractAddress)
        {
            Web3 = web3;
            ContractHandler = web3.Eth.GetContractHandler(contractAddress);
        }

        public OrderBookReaderService(IWeb3 web3, string contractAddress)
        {
            Web3 = web3;
            ContractHandler = web3.Eth.GetContractHandler(contractAddress);
        }

        public Task<GetDecreaseOrdersOutputDTO> GetDecreaseOrdersQueryAsync(
            GetDecreaseOrdersFunction getDecreaseOrdersFunction, BlockParameter blockParameter = null)
        {
            return ContractHandler
                .QueryDeserializingToObjectAsync<GetDecreaseOrdersFunction, GetDecreaseOrdersOutputDTO>(
                    getDecreaseOrdersFunction, blockParameter);
        }

        public Task<GetDecreaseOrdersOutputDTO> GetDecreaseOrdersQueryAsync(string orderBookAddress, string account,
            List<BigInteger> indices, BlockParameter blockParameter = null)
        {
            var getDecreaseOrdersFunction = new GetDecreaseOrdersFunction();
            getDecreaseOrdersFunction.OrderBookAddress = orderBookAddress;
            getDecreaseOrdersFunction.Account = account;
            getDecreaseOrdersFunction.Indices = indices;

            return ContractHandler
                .QueryDeserializingToObjectAsync<GetDecreaseOrdersFunction, GetDecreaseOrdersOutputDTO>(
                    getDecreaseOrdersFunction, blockParameter);
        }

        public Task<GetIncreaseOrdersOutputDTO> GetIncreaseOrdersQueryAsync(
            GetIncreaseOrdersFunction getIncreaseOrdersFunction, BlockParameter blockParameter = null)
        {
            return ContractHandler
                .QueryDeserializingToObjectAsync<GetIncreaseOrdersFunction, GetIncreaseOrdersOutputDTO>(
                    getIncreaseOrdersFunction, blockParameter);
        }

        public Task<GetIncreaseOrdersOutputDTO> GetIncreaseOrdersQueryAsync(string orderBookAddress, string account,
            List<BigInteger> indices, BlockParameter blockParameter = null)
        {
            var getIncreaseOrdersFunction = new GetIncreaseOrdersFunction();
            getIncreaseOrdersFunction.OrderBookAddress = orderBookAddress;
            getIncreaseOrdersFunction.Account = account;
            getIncreaseOrdersFunction.Indices = indices;

            return ContractHandler
                .QueryDeserializingToObjectAsync<GetIncreaseOrdersFunction, GetIncreaseOrdersOutputDTO>(
                    getIncreaseOrdersFunction, blockParameter);
        }

        public Task<GetSwapOrdersOutputDTO> GetSwapOrdersQueryAsync(GetSwapOrdersFunction getSwapOrdersFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryDeserializingToObjectAsync<GetSwapOrdersFunction, GetSwapOrdersOutputDTO>(
                getSwapOrdersFunction, blockParameter);
        }

        public Task<GetSwapOrdersOutputDTO> GetSwapOrdersQueryAsync(string orderBookAddress, string account,
            List<BigInteger> indices, BlockParameter blockParameter = null)
        {
            var getSwapOrdersFunction = new GetSwapOrdersFunction();
            getSwapOrdersFunction.OrderBookAddress = orderBookAddress;
            getSwapOrdersFunction.Account = account;
            getSwapOrdersFunction.Indices = indices;

            return ContractHandler.QueryDeserializingToObjectAsync<GetSwapOrdersFunction, GetSwapOrdersOutputDTO>(
                getSwapOrdersFunction, blockParameter);
        }
    }
}