using System;
using System.Linq;
using System.Threading.Tasks;
using Knoks.Core.Data.Dao;
using Knoks.Core.Data.Interfaces;
using Knoks.Core.Entities;
using Knoks.Core.Entities.Args.AccountTransactions;
using Knoks.Core.Entities.Settings;
using Knoks.Core.Logic.Interfaces;
using Knoks.Framework.Services;
using AccountTransactionType = Knoks.Core.Entities.Args.AccountTransactions.AccountTransactionType;

namespace Knoks.Core.Logic.Managers
{
    public class AccountTransactionManager : IAccountTransactionManager
    {
        private readonly IUserManager _userManager;
        private readonly IAccountTransactionDao _accountTransactionsDao;

        public AccountTransactionManager(IUserManager userManager, IAccountTransactionDao accountTransactionsDao)
        {
            _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
            _accountTransactionsDao = accountTransactionsDao ?? throw new ArgumentNullException(nameof(accountTransactionsDao));
        }

        public async Task<AccountTransaction> GetLatestDepositEvent()
        {
            return await _accountTransactionsDao.GetLatestEvent(AccountTransactionType.Deposit);
        }

        private  async Task TransferMoney(User fromUser, Account fromAccount, User toUser, Account toAccount, long? knokId, decimal amount, decimal? amountUsd,
            AccountTransactionType transactionType, string comment = null)
        {
            var fromArgs = new AccountSetBalanceArgs()
            {
                AccountId = fromAccount.AccountId,
                Amount = amount,
                AmountUSD = amountUsd,
                Comment = comment,
                UserId = fromUser.UserId,
                WalletAddress = fromAccount.WalletAddress,
                AccountTransactionTypeId = (short)transactionType
            };

            var toArgs = new AccountSetBalanceArgs()
            {
                AccountId = toAccount.AccountId,
                Amount = amount,
                AmountUSD = amountUsd,
                Comment = comment,
                UserId = toUser.UserId,
                WalletAddress = toAccount.WalletAddress,
                AccountTransactionTypeId = (short)transactionType
            };

            await _accountTransactionsDao.TransferMoney(fromArgs, toArgs, knokId);
        }

        private async Task ExternalTransferMoney(User fromUser, Account fromAccount, User toUser, Account toAccount, decimal amount, decimal? amountUsd,
            string comment, string externalReferenceId)
        {
            var fromArgs = new AccountSetBalanceArgs()
            {
                AccountId = fromAccount.AccountId,
                Amount = amount,
                AmountUSD = amountUsd,
                Comment = comment,
                ExternalReferenceId = externalReferenceId,
                UserId = fromUser.UserId,
                WalletAddress = fromAccount.WalletAddress,
                AccountTransactionTypeId = (short)AccountTransactionType.Withdraw
            };

            var toArgs = new AccountSetBalanceArgs()
            {
                AccountId = toAccount.AccountId,
                Amount = amount,
                AmountUSD = amountUsd,
                Comment = comment,
                ExternalReferenceId = externalReferenceId,
                UserId = toUser.UserId,
                WalletAddress = toAccount.WalletAddress,
                AccountTransactionTypeId = (short)AccountTransactionType.Deposit
            };

            await _accountTransactionsDao.TransferMoney(fromArgs, toArgs, null);
        }

        //public async Task ExecutePublishKnokTransaction(User knokerUser, Account knokerAccount, long knokId, decimal amount,
        //    decimal? amountUsd = null)
        //{
        //    await TransferMoney(knokerUser, knokerAccount, _platformUser, _platformUserAccount, knokId, amount, amountUsd, AccountTransactionType.PublishKnok);
        //}

        //public async Task ActivateFreeCredit(User targetUser, Account targetUserAccount)
        //{
        //    await TransferMoney(_userManager.PlatformUser, _userManager.PlatformUserAccount, targetUser, targetUserAccount, null, _settings.NewUserFreeCreditAmount, null, AccountTransactionType.FreeTokensCredit);
        //}

        public async Task Transfer(User fromUser, Account fromUserAccount, User toUser, Account toUserAccount, decimal amount, decimal? amountUsd,
            string externalReferenceId, ulong blockNumber)
        {
            await ExternalTransferMoney(fromUser, fromUserAccount, toUser, toUserAccount, amount, amountUsd, blockNumber.ToString(), externalReferenceId);
        }

        //public async Task Deposit(User targetUser, Account targetUserAccount, decimal amount, decimal amountUsd, string externalReferenceId, ulong blockNumber, int? operatorId = null)
        //{
        //    await TransferMoney(_userManager.PlatformUser, _userManager.PlatformUserAccount, targetUser, targetUserAccount, null, amount, amountUsd, AccountTransactionType.Deposit,
        //        blockNumber.ToString(), externalReferenceId);
        //}

        //public async Task Withdraw(User targetUser, Account targetUserAccount, decimal amount, decimal amountUsd, string externalReferenceId, ulong blockNumber, int? operatorId = null)
        //{
        //    await TransferMoney(targetUser, targetUserAccount, _userManager.PlatformUser, _userManager.PlatformUserAccount, null, amount, amountUsd, AccountTransactionType.Withdraw,
        //        blockNumber.ToString(), externalReferenceId);
        //}

        //public async Task ExecuteKnokerWinsKnokTransaction(User knokerUser, Account knokerAccount, decimal amount, decimal? amountUsd = null)
        //{
        //    await TransferMoney(_platformUser, _platformUserAccount, knokerUser, knokerAccount, amount, amountUsd, AccountTransactionType.KnokerWinsToken);
        //}

        //public async Task ExecuteUserBuyKnokTransaction(User user, Account account, long knokId, decimal amount, decimal? amountUsd = null)
        //{
        //    await TransferMoney(user, account, _platformUser, _platformUserAccount, knokId, amount, amountUsd, AccountTransactionType.UserBuyKnok);
        //}

        //public async Task ExecuteUserRefundFailedKnokTransaction(User user, Account account, decimal amount, decimal? amountUsd = null)
        //{
        //    await TransferMoney(_platformUser, _platformUserAccount, user, account, amount, amountUsd, AccountTransactionType.UserRefundToken);
        //}
    }
}