using Binance.TradeRobot.Business.Extensions;
using Binance.TradeRobot.Common.DI;
using Binance.TradeRobot.Common.Extensions;
using Binance.TradeRobot.Model.Base;
using Binance.TradeRobot.Model.Db;
using Binance.TradeRobot.Model.Dto;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Data.Common;
using Yitter.IdGenerator;

namespace Binance.TradeRobot.Business
{
    [BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)]
    public class RobotBusiness : BaseBusiness
    {
        public RobotBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache) : base(fsql, logManager, idGenerator, memoryCache)
        {

        }

        /// <summary>
        /// 检查机器人注册条件
        /// </summary>
        /// <param name="addRobotRequest"></param>
        /// <param name="exchangeAPIKey"></param>
        /// <exception cref="BusinessException"></exception>
        private void CheckRobotRegister(AddRobotRequest addRobotRequest, out ExchangeAPIKey exchangeAPIKey)
        {
            exchangeAPIKey = null;
            if (string.IsNullOrEmpty(addRobotRequest.Symbol) || addRobotRequest.ExchangeAPIKeyId == 0)
                throw new BusinessException("参数不全");
            exchangeAPIKey = fsql.Select<ExchangeAPIKey>(addRobotRequest.ExchangeAPIKeyId).ToOne();
            if (exchangeAPIKey == null)
                throw new BusinessException("选择的APIKey不存在");
            if (exchangeAPIKey.RobotId != null)
                throw new BusinessException("APIKey已被其他机器人使用");

            var accountId = exchangeAPIKey.AccountId;
            if (fsql.Select<ExchangeAccount, ExchangeAPIKey, Robot>().InnerJoin((ea, ek, r) => ea.Id == ek.AccountId)
                                                                     .LeftJoin((ea, ek, r) => ek.RobotId == r.Id)
                                                                     .Where((ea, ek, r) => ea.Id == accountId &&
                                                                                           r.Symbol == addRobotRequest.Symbol).Any())
                throw new BusinessException("同一个交易所账号下只允许存在一个交易对");
        }

        public void StartRobot(long robotId)
        {

        }

        public void StopRobot(long robotId)
        {

        }

        /// <summary>
        /// 添加机器人和账户
        /// </summary>
        /// <param name="addRobotRequest"></param>
        /// <param name="tran"></param>
        /// <returns>机器人Id</returns>
        private long AddRobotWithTran(AddRobotRequest addRobotRequest, DbTransaction tran)
        {
            var robotId = idGenerator.NewLong();
            fsql.Insert(new Robot()
            {
                Id = robotId,
                Symbol = addRobotRequest.Symbol,
                TradePolicy = addRobotRequest.TradePolicy,
                BusinessType = addRobotRequest.TradePolicy.GetBusinessType(),
                ExchangeId = addRobotRequest.ExchangeId,
                CreateTime = DateTime.Now,
                RunningTime = 0,
                State = Enums.RobotState.Stop
            }).WithTransaction(tran).ExecuteAffrows();

            fsql.Insert(new RobotAccount()
            {
                Id = idGenerator.NewLong(),
                RobotId = robotId
            }).WithTransaction(tran).ExecuteAffrows();

            fsql.Update<ExchangeAPIKey>(addRobotRequest.ExchangeAPIKeyId).WithTransaction(tran).Set(ek => ek.RobotId, robotId).ExecuteAffrows();

            return robotId;
        }

        /// <summary>
        /// 添加金字塔策略机器人
        /// </summary>
        /// <param name="addRobotRequest"></param>
        public void AddPyramidPolicyRobot(AddRobotRequest addRobotRequest)
        {
            CheckRobotRegister(addRobotRequest, out ExchangeAPIKey exchangeAPIKey);
            var pyramidPolicy = new PyramidPolicy();
            pyramidPolicy.Id = idGenerator.NewLong();
            fsql.Transaction(() =>
            {
                var tran = fsql.Ado.TransactionCurrentThread;
                pyramidPolicy.RobotId = AddRobotWithTran(addRobotRequest, tran);
                fsql.Insert(pyramidPolicy).ExecuteAffrows();
            });

            //调整仓位杠杆倍数
        }

        /// <summary>
        /// 添加动2.1策略机器人
        /// </summary>
        /// <param name="addRobotRequest"></param>
        public void AddD21PolicyRobot(AddRobotRequest addRobotRequest)
        {
            CheckRobotRegister(addRobotRequest, out _);
            var d21Policy = new D21Policy()
            {
                Id = idGenerator.NewLong(),
                CreateTime = DateTime.Now,
                ExecutionMode = Enums.ExecutionMode.Both,
                IsEnabledIncreasePurchase = true,
                IsEnableRemedyForErrorCrossSignal = true
            };
            fsql.Transaction(() =>
            {
                var tran = fsql.Ado.TransactionCurrentThread;
                d21Policy.RobotId = AddRobotWithTran(addRobotRequest, tran);
                fsql.Insert(d21Policy).ExecuteAffrows();
            });
        }

        /// <summary>
        /// 获取动2.1策略机器人列表
        /// </summary>
        /// <param name="robotState">机器人状态</param>
        /// <param name="signalPeriod">信号周期</param>
        /// <param name="symbol">交易对</param>
        /// <param name="isLoadRecentTradeProfit">是否加载近期交易利润,默认true</param>
        /// <param name="isLoadAPIKey">是否加载机器人绑定的APIKey,默认false</param>
        /// <returns></returns>
        public IList<D21PolicyRobotResponse> GetD21PolicyRobotList(Enums.RobotState? robotState = null,
                                                                   Enums.SignalPeriod? signalPeriod = null,
                                                                   string symbol = "",
                                                                   bool isLoadRecentTradeProfit = true,
                                                                   bool isLoadAPIKey = false)
        {
            var robotList = fsql.Select<Robot, RobotAccount, D21Policy, ExchangeAPIKey>().InnerJoin((r, ra, d, e) => r.Id == ra.RobotId)
                                                                                         .InnerJoin((r, ra, d, e) => r.Id == d.RobotId)
                                                                                         .InnerJoin((r, ra, d, e) => r.Id == e.RobotId)
                                                                                         .WhereIf(robotState != null, (r, ra, d, e) => r.State == robotState)
                                                                                         .WhereIf(signalPeriod != null, (r, ra, d, e) => d.PeriodicSignal == signalPeriod)
                                                                                         .WhereIf(!string.IsNullOrEmpty(symbol), (r, ra, d, e) => r.Symbol == symbol)
                                                                                         .Where((r, ra, d, e) => r.TradePolicy == Enums.TradePolicy.动量趋势v21)
                                                                                         .ToList((r, ra, d, e) => new Robot()
                                                                                         {
                                                                                             Id = r.Id,
                                                                                             BusinessType = r.BusinessType,
                                                                                             ExchangeId = r.ExchangeId,
                                                                                             Symbol = r.Symbol,
                                                                                             State = r.State,
                                                                                             RunningTime = r.RunningTime,
                                                                                             CreateTime = r.CreateTime,
                                                                                             TradePolicy = r.TradePolicy,

                                                                                             RobotAccountId = ra.Id,
                                                                                             ClosePositionCount = ra.ClosePositionCount,
                                                                                             WinCount = ra.WinCount,
                                                                                             LoanAmount = ra.LoanAmount,
                                                                                             SoptCurrentcyAmount = ra.SoptCurrentcyAmount,
                                                                                             SpotCurrencyQuantity = ra.SpotCurrencyQuantity,
                                                                                             TotalProfit = ra.TotalProfit,

                                                                                             ExchangeAccountId = e.AccountId,
                                                                                             ExchangeAPIKey = e.APIKey,
                                                                                             ExchangeSecretKey = e.SecretKey,

                                                                                             D21ExecutionMode = d.ExecutionMode,
                                                                                             D21IsEnabledIncreasePurchase = d.IsEnabledIncreasePurchase,
                                                                                             D21IsEnableRemedyForErrorCrossSignal = d.IsEnableRemedyForErrorCrossSignal,
                                                                                             D21MaxFollowPurchaseRatio = d.MaxFollowPurchaseRatio,
                                                                                             D21PeriodicSignal = d.PeriodicSignal,
                                                                                             D21PolicyId = d.Id,
                                                                                             D21Position = d.Position,
                                                                                             D21Assets = d.Assets,
                                                                                             D21Level1PositionStopLossRatio = d.Level1PositionStopLossRatio,
                                                                                             D21Level1PriceStopLossRatio = d.Level1PriceStopLossRatio,
                                                                                             D21Level2PositionStopLossRatio = d.Level2PositionStopLossRatio,
                                                                                             D21Level2PriceStopLossRatio = d.Level2PriceStopLossRatio,
                                                                                             D21MaxExchangeLoanRatio = d.MaxExchangeLoanRatio,
                                                                                             D21MaxSystemLoanRatio = d.MaxSystemLoanRatio,
                                                                                             D21CreateTime = d.CreateTime
                                                                                         }).Map<IList<D21PolicyRobotResponse>>();
            if (isLoadRecentTradeProfit)
            {
                //统计近期订单利润
            }

            if (!isLoadAPIKey)
            {
                foreach (var r in robotList)
                    r.ExchangeAPIKey = null;
            }

            return robotList;
        }
    }
}