using System.Numerics;
using Managing.Tools.ABI.Reader.ContractDefinition;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Web3;

namespace Managing.Tools.ABI.Reader
{
    public class ReaderService : ContractWeb3ServiceBase
    {
        public static Task<TransactionReceipt> DeployContractAndWaitForReceiptAsync(IWeb3 web3,
            ReaderDeployment readerDeployment, CancellationTokenSource cancellationTokenSource = null)
        {
            return web3.Eth.GetContractDeploymentHandler<ReaderDeployment>()
                .SendRequestAndWaitForReceiptAsync(readerDeployment, cancellationTokenSource);
        }

        public static Task<string> DeployContractAsync(IWeb3 web3, ReaderDeployment readerDeployment)
        {
            return web3.Eth.GetContractDeploymentHandler<ReaderDeployment>().SendRequestAsync(readerDeployment);
        }

        public static async Task<ReaderService> DeployContractAndGetServiceAsync(IWeb3 web3,
            ReaderDeployment readerDeployment, CancellationTokenSource cancellationTokenSource = null)
        {
            var receipt = await DeployContractAndWaitForReceiptAsync(web3, readerDeployment, cancellationTokenSource);
            return new ReaderService(web3, receipt.ContractAddress);
        }

        public ReaderService(IWeb3 web3, string contractAddress) : base(web3, contractAddress)
        {
        }

        public Task<BigInteger> BasisPointsDivisorQueryAsync(BasisPointsDivisorFunction basisPointsDivisorFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<BasisPointsDivisorFunction, BigInteger>(basisPointsDivisorFunction,
                blockParameter);
        }


        public Task<BigInteger> BasisPointsDivisorQueryAsync(BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<BasisPointsDivisorFunction, BigInteger>(null, blockParameter);
        }

        public Task<BigInteger> PositionPropsLengthQueryAsync(PositionPropsLengthFunction positionPropsLengthFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<PositionPropsLengthFunction, BigInteger>(positionPropsLengthFunction,
                blockParameter);
        }


        public Task<BigInteger> PositionPropsLengthQueryAsync(BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<PositionPropsLengthFunction, BigInteger>(null, blockParameter);
        }

        public Task<BigInteger> PricePrecisionQueryAsync(PricePrecisionFunction pricePrecisionFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<PricePrecisionFunction, BigInteger>(pricePrecisionFunction,
                blockParameter);
        }


        public Task<BigInteger> PricePrecisionQueryAsync(BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<PricePrecisionFunction, BigInteger>(null, blockParameter);
        }

        public Task<BigInteger> UsdgDecimalsQueryAsync(UsdgDecimalsFunction usdgDecimalsFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<UsdgDecimalsFunction, BigInteger>(usdgDecimalsFunction, blockParameter);
        }


        public Task<BigInteger> UsdgDecimalsQueryAsync(BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<UsdgDecimalsFunction, BigInteger>(null, blockParameter);
        }

        public Task<GetAmountOutOutputDTO> GetAmountOutQueryAsync(GetAmountOutFunction getAmountOutFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryDeserializingToObjectAsync<GetAmountOutFunction, GetAmountOutOutputDTO>(
                getAmountOutFunction, blockParameter);
        }

        public Task<GetAmountOutOutputDTO> GetAmountOutQueryAsync(string vault, string tokenIn, string tokenOut,
            BigInteger amountIn, BlockParameter blockParameter = null)
        {
            var getAmountOutFunction = new GetAmountOutFunction();
            getAmountOutFunction.Vault = vault;
            getAmountOutFunction.TokenIn = tokenIn;
            getAmountOutFunction.TokenOut = tokenOut;
            getAmountOutFunction.AmountIn = amountIn;

            return ContractHandler.QueryDeserializingToObjectAsync<GetAmountOutFunction, GetAmountOutOutputDTO>(
                getAmountOutFunction, blockParameter);
        }

        public Task<GetFeeBasisPointsOutputDTO> GetFeeBasisPointsQueryAsync(
            GetFeeBasisPointsFunction getFeeBasisPointsFunction, BlockParameter blockParameter = null)
        {
            return ContractHandler
                .QueryDeserializingToObjectAsync<GetFeeBasisPointsFunction, GetFeeBasisPointsOutputDTO>(
                    getFeeBasisPointsFunction, blockParameter);
        }

        public Task<GetFeeBasisPointsOutputDTO> GetFeeBasisPointsQueryAsync(string vault, string tokenIn,
            string tokenOut, BigInteger amountIn, BlockParameter blockParameter = null)
        {
            var getFeeBasisPointsFunction = new GetFeeBasisPointsFunction();
            getFeeBasisPointsFunction.Vault = vault;
            getFeeBasisPointsFunction.TokenIn = tokenIn;
            getFeeBasisPointsFunction.TokenOut = tokenOut;
            getFeeBasisPointsFunction.AmountIn = amountIn;

            return ContractHandler
                .QueryDeserializingToObjectAsync<GetFeeBasisPointsFunction, GetFeeBasisPointsOutputDTO>(
                    getFeeBasisPointsFunction, blockParameter);
        }

        public Task<List<BigInteger>> GetFeesQueryAsync(GetFeesFunction getFeesFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetFeesFunction, List<BigInteger>>(getFeesFunction, blockParameter);
        }


        public Task<List<BigInteger>> GetFeesQueryAsync(string vault, List<string> tokens,
            BlockParameter blockParameter = null)
        {
            var getFeesFunction = new GetFeesFunction();
            getFeesFunction.Vault = vault;
            getFeesFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetFeesFunction, List<BigInteger>>(getFeesFunction, blockParameter);
        }

        public Task<List<BigInteger>> GetFullVaultTokenInfoQueryAsync(
            GetFullVaultTokenInfoFunction getFullVaultTokenInfoFunction, BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetFullVaultTokenInfoFunction, List<BigInteger>>(
                getFullVaultTokenInfoFunction, blockParameter);
        }


        public Task<List<BigInteger>> GetFullVaultTokenInfoQueryAsync(string vault, string weth, BigInteger usdgAmount,
            List<string> tokens, BlockParameter blockParameter = null)
        {
            var getFullVaultTokenInfoFunction = new GetFullVaultTokenInfoFunction();
            getFullVaultTokenInfoFunction.Vault = vault;
            getFullVaultTokenInfoFunction.Weth = weth;
            getFullVaultTokenInfoFunction.UsdgAmount = usdgAmount;
            getFullVaultTokenInfoFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetFullVaultTokenInfoFunction, List<BigInteger>>(
                getFullVaultTokenInfoFunction, blockParameter);
        }

        public Task<List<BigInteger>> GetFundingRatesQueryAsync(GetFundingRatesFunction getFundingRatesFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetFundingRatesFunction, List<BigInteger>>(getFundingRatesFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetFundingRatesQueryAsync(string vault, string weth, List<string> tokens,
            BlockParameter blockParameter = null)
        {
            var getFundingRatesFunction = new GetFundingRatesFunction();
            getFundingRatesFunction.Vault = vault;
            getFundingRatesFunction.Weth = weth;
            getFundingRatesFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetFundingRatesFunction, List<BigInteger>>(getFundingRatesFunction,
                blockParameter);
        }

        public Task<BigInteger> GetMaxAmountInQueryAsync(GetMaxAmountInFunction getMaxAmountInFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetMaxAmountInFunction, BigInteger>(getMaxAmountInFunction,
                blockParameter);
        }


        public Task<BigInteger> GetMaxAmountInQueryAsync(string vault, string tokenIn, string tokenOut,
            BlockParameter blockParameter = null)
        {
            var getMaxAmountInFunction = new GetMaxAmountInFunction();
            getMaxAmountInFunction.Vault = vault;
            getMaxAmountInFunction.TokenIn = tokenIn;
            getMaxAmountInFunction.TokenOut = tokenOut;

            return ContractHandler.QueryAsync<GetMaxAmountInFunction, BigInteger>(getMaxAmountInFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetPairInfoQueryAsync(GetPairInfoFunction getPairInfoFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetPairInfoFunction, List<BigInteger>>(getPairInfoFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetPairInfoQueryAsync(string factory, List<string> tokens,
            BlockParameter blockParameter = null)
        {
            var getPairInfoFunction = new GetPairInfoFunction();
            getPairInfoFunction.Factory = factory;
            getPairInfoFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetPairInfoFunction, List<BigInteger>>(getPairInfoFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetPositionsQueryAsync(GetPositionsFunction getPositionsFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetPositionsFunction, List<BigInteger>>(getPositionsFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetPositionsQueryAsync(string vault, string account,
            List<string> collateralTokens, List<string> indexTokens, List<bool> isLong,
            BlockParameter blockParameter = null)
        {
            var getPositionsFunction = new GetPositionsFunction();
            getPositionsFunction.Vault = vault;
            getPositionsFunction.Account = account;
            getPositionsFunction.CollateralTokens = collateralTokens;
            getPositionsFunction.IndexTokens = indexTokens;
            getPositionsFunction.IsLong = isLong;

            return ContractHandler.QueryAsync<GetPositionsFunction, List<BigInteger>>(getPositionsFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetPricesQueryAsync(GetPricesFunction getPricesFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetPricesFunction, List<BigInteger>>(getPricesFunction, blockParameter);
        }


        public Task<List<BigInteger>> GetPricesQueryAsync(string priceFeed, List<string> tokens,
            BlockParameter blockParameter = null)
        {
            var getPricesFunction = new GetPricesFunction();
            getPricesFunction.PriceFeed = priceFeed;
            getPricesFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetPricesFunction, List<BigInteger>>(getPricesFunction, blockParameter);
        }

        public Task<List<BigInteger>> GetStakingInfoQueryAsync(GetStakingInfoFunction getStakingInfoFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetStakingInfoFunction, List<BigInteger>>(getStakingInfoFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetStakingInfoQueryAsync(string account, List<string> yieldTrackers,
            BlockParameter blockParameter = null)
        {
            var getStakingInfoFunction = new GetStakingInfoFunction();
            getStakingInfoFunction.Account = account;
            getStakingInfoFunction.YieldTrackers = yieldTrackers;

            return ContractHandler.QueryAsync<GetStakingInfoFunction, List<BigInteger>>(getStakingInfoFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetTokenBalancesQueryAsync(GetTokenBalancesFunction getTokenBalancesFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetTokenBalancesFunction, List<BigInteger>>(getTokenBalancesFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetTokenBalancesQueryAsync(string account, List<string> tokens,
            BlockParameter blockParameter = null)
        {
            var getTokenBalancesFunction = new GetTokenBalancesFunction();
            getTokenBalancesFunction.Account = account;
            getTokenBalancesFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetTokenBalancesFunction, List<BigInteger>>(getTokenBalancesFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetTokenBalancesWithSuppliesQueryAsync(
            GetTokenBalancesWithSuppliesFunction getTokenBalancesWithSuppliesFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetTokenBalancesWithSuppliesFunction, List<BigInteger>>(
                getTokenBalancesWithSuppliesFunction, blockParameter);
        }


        public Task<List<BigInteger>> GetTokenBalancesWithSuppliesQueryAsync(string account, List<string> tokens,
            BlockParameter blockParameter = null)
        {
            var getTokenBalancesWithSuppliesFunction = new GetTokenBalancesWithSuppliesFunction();
            getTokenBalancesWithSuppliesFunction.Account = account;
            getTokenBalancesWithSuppliesFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetTokenBalancesWithSuppliesFunction, List<BigInteger>>(
                getTokenBalancesWithSuppliesFunction, blockParameter);
        }

        public Task<BigInteger> GetTokenSupplyQueryAsync(GetTokenSupplyFunction getTokenSupplyFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetTokenSupplyFunction, BigInteger>(getTokenSupplyFunction,
                blockParameter);
        }


        public Task<BigInteger> GetTokenSupplyQueryAsync(string token, List<string> excludedAccounts,
            BlockParameter blockParameter = null)
        {
            var getTokenSupplyFunction = new GetTokenSupplyFunction();
            getTokenSupplyFunction.Token = token;
            getTokenSupplyFunction.ExcludedAccounts = excludedAccounts;

            return ContractHandler.QueryAsync<GetTokenSupplyFunction, BigInteger>(getTokenSupplyFunction,
                blockParameter);
        }

        public Task<BigInteger> GetTotalBalanceQueryAsync(GetTotalBalanceFunction getTotalBalanceFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetTotalBalanceFunction, BigInteger>(getTotalBalanceFunction,
                blockParameter);
        }


        public Task<BigInteger> GetTotalBalanceQueryAsync(string token, List<string> accounts,
            BlockParameter blockParameter = null)
        {
            var getTotalBalanceFunction = new GetTotalBalanceFunction();
            getTotalBalanceFunction.Token = token;
            getTotalBalanceFunction.Accounts = accounts;

            return ContractHandler.QueryAsync<GetTotalBalanceFunction, BigInteger>(getTotalBalanceFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetTotalStakedQueryAsync(GetTotalStakedFunction getTotalStakedFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetTotalStakedFunction, List<BigInteger>>(getTotalStakedFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetTotalStakedQueryAsync(List<string> yieldTokens,
            BlockParameter blockParameter = null)
        {
            var getTotalStakedFunction = new GetTotalStakedFunction();
            getTotalStakedFunction.YieldTokens = yieldTokens;

            return ContractHandler.QueryAsync<GetTotalStakedFunction, List<BigInteger>>(getTotalStakedFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetVaultTokenInfoQueryAsync(GetVaultTokenInfoFunction getVaultTokenInfoFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetVaultTokenInfoFunction, List<BigInteger>>(getVaultTokenInfoFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetVaultTokenInfoQueryAsync(string vault, string weth, BigInteger usdgAmount,
            List<string> tokens, BlockParameter blockParameter = null)
        {
            var getVaultTokenInfoFunction = new GetVaultTokenInfoFunction();
            getVaultTokenInfoFunction.Vault = vault;
            getVaultTokenInfoFunction.Weth = weth;
            getVaultTokenInfoFunction.UsdgAmount = usdgAmount;
            getVaultTokenInfoFunction.Tokens = tokens;

            return ContractHandler.QueryAsync<GetVaultTokenInfoFunction, List<BigInteger>>(getVaultTokenInfoFunction,
                blockParameter);
        }

        public Task<List<BigInteger>> GetVaultTokenInfoV2QueryAsync(
            GetVaultTokenInfoV2Function getVaultTokenInfoV2Function, BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetVaultTokenInfoV2Function, List<BigInteger>>(
                getVaultTokenInfoV2Function, blockParameter);
        }


        public Task<List<BigInteger>> GetVaultTokenInfoV2QueryAsync(string vault, string weth, BigInteger usdgAmount,
            List<string> tokens, BlockParameter blockParameter = null)
        {
            var getVaultTokenInfoV2Function = new GetVaultTokenInfoV2Function();
            getVaultTokenInfoV2Function.Vault = vault;
            getVaultTokenInfoV2Function.Weth = weth;
            getVaultTokenInfoV2Function.UsdgAmount = usdgAmount;
            getVaultTokenInfoV2Function.Tokens = tokens;

            return ContractHandler.QueryAsync<GetVaultTokenInfoV2Function, List<BigInteger>>(
                getVaultTokenInfoV2Function, blockParameter);
        }

        public Task<List<BigInteger>> GetVestingInfoQueryAsync(GetVestingInfoFunction getVestingInfoFunction,
            BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GetVestingInfoFunction, List<BigInteger>>(getVestingInfoFunction,
                blockParameter);
        }


        public Task<List<BigInteger>> GetVestingInfoQueryAsync(string account, List<string> vesters,
            BlockParameter blockParameter = null)
        {
            var getVestingInfoFunction = new GetVestingInfoFunction();
            getVestingInfoFunction.Account = account;
            getVestingInfoFunction.Vesters = vesters;

            return ContractHandler.QueryAsync<GetVestingInfoFunction, List<BigInteger>>(getVestingInfoFunction,
                blockParameter);
        }

        public Task<string> GovQueryAsync(GovFunction govFunction, BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GovFunction, string>(govFunction, blockParameter);
        }


        public Task<string> GovQueryAsync(BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<GovFunction, string>(null, blockParameter);
        }

        public Task<bool> HasMaxGlobalShortSizesQueryAsync(
            HasMaxGlobalShortSizesFunction hasMaxGlobalShortSizesFunction, BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<HasMaxGlobalShortSizesFunction, bool>(hasMaxGlobalShortSizesFunction,
                blockParameter);
        }


        public Task<bool> HasMaxGlobalShortSizesQueryAsync(BlockParameter blockParameter = null)
        {
            return ContractHandler.QueryAsync<HasMaxGlobalShortSizesFunction, bool>(null, blockParameter);
        }

        public Task<string> SetConfigRequestAsync(SetConfigFunction setConfigFunction)
        {
            return ContractHandler.SendRequestAsync(setConfigFunction);
        }

        public Task<TransactionReceipt> SetConfigRequestAndWaitForReceiptAsync(SetConfigFunction setConfigFunction,
            CancellationTokenSource cancellationToken = null)
        {
            return ContractHandler.SendRequestAndWaitForReceiptAsync(setConfigFunction, cancellationToken);
        }

        public Task<string> SetConfigRequestAsync(bool hasMaxGlobalShortSizes)
        {
            var setConfigFunction = new SetConfigFunction();
            setConfigFunction.HasMaxGlobalShortSizes = hasMaxGlobalShortSizes;

            return ContractHandler.SendRequestAsync(setConfigFunction);
        }

        public Task<TransactionReceipt> SetConfigRequestAndWaitForReceiptAsync(bool hasMaxGlobalShortSizes,
            CancellationTokenSource cancellationToken = null)
        {
            var setConfigFunction = new SetConfigFunction();
            setConfigFunction.HasMaxGlobalShortSizes = hasMaxGlobalShortSizes;

            return ContractHandler.SendRequestAndWaitForReceiptAsync(setConfigFunction, cancellationToken);
        }

        public Task<string> SetGovRequestAsync(SetGovFunction setGovFunction)
        {
            return ContractHandler.SendRequestAsync(setGovFunction);
        }

        public Task<TransactionReceipt> SetGovRequestAndWaitForReceiptAsync(SetGovFunction setGovFunction,
            CancellationTokenSource cancellationToken = null)
        {
            return ContractHandler.SendRequestAndWaitForReceiptAsync(setGovFunction, cancellationToken);
        }

        public Task<string> SetGovRequestAsync(string gov)
        {
            var setGovFunction = new SetGovFunction();
            setGovFunction.Gov = gov;

            return ContractHandler.SendRequestAsync(setGovFunction);
        }

        public Task<TransactionReceipt> SetGovRequestAndWaitForReceiptAsync(string gov,
            CancellationTokenSource cancellationToken = null)
        {
            var setGovFunction = new SetGovFunction();
            setGovFunction.Gov = gov;

            return ContractHandler.SendRequestAndWaitForReceiptAsync(setGovFunction, cancellationToken);
        }

        public override List<Type> GetAllFunctionTypes()
        {
            return new List<Type>
            {
                typeof(BasisPointsDivisorFunction),
                typeof(PositionPropsLengthFunction),
                typeof(PricePrecisionFunction),
                typeof(UsdgDecimalsFunction),
                typeof(GetAmountOutFunction),
                typeof(GetFeeBasisPointsFunction),
                typeof(GetFeesFunction),
                typeof(GetFullVaultTokenInfoFunction),
                typeof(GetFundingRatesFunction),
                typeof(GetMaxAmountInFunction),
                typeof(GetPairInfoFunction),
                typeof(GetPositionsFunction),
                typeof(GetPricesFunction),
                typeof(GetStakingInfoFunction),
                typeof(GetTokenBalancesFunction),
                typeof(GetTokenBalancesWithSuppliesFunction),
                typeof(GetTokenSupplyFunction),
                typeof(GetTotalBalanceFunction),
                typeof(GetTotalStakedFunction),
                typeof(GetVaultTokenInfoFunction),
                typeof(GetVaultTokenInfoV2Function),
                typeof(GetVestingInfoFunction),
                typeof(GovFunction),
                typeof(HasMaxGlobalShortSizesFunction),
                typeof(SetConfigFunction),
                typeof(SetGovFunction)
            };
        }

        public override List<Type> GetAllEventTypes()
        {
            return new List<Type>();
        }

        public override List<Type> GetAllErrorTypes()
        {
            return new List<Type>();
        }
    }
}