using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Service;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Domain;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

namespace Hncore.Pass.Vpn.Service
{
    public class AgentService:IFindService
    {
        CourseContext m_DbContext;
        IHttpClientFactory m_HttpClientFactory;
        protected ProductService m_ProductService;
        protected ProductPackageService m_ProductPackageService;
        protected ProductPackageUnitService m_ProductPackageUnitService;
        protected ProductEntity m_Product;
        protected ProductAccountChargeService m_AccountChargeService;
        protected Dictionary<string,AgentClientBaseService> m_MapAgentClient=new Dictionary<string, AgentClientBaseService>();
        public AgentService(ProductService _ProductService
            , ProductPackageService _ProductPackageService
            , ProductPackageUnitService _ProductPackageUnitService          
            , ProductAccountChargeService _AccountChargeService
            , IHttpClientFactory httpClientFactory
            , CourseContext _DbContext)
        {
            m_HttpClientFactory = httpClientFactory;
            m_ProductService = _ProductService;
            m_ProductPackageService = _ProductPackageService;
            m_ProductPackageUnitService = _ProductPackageUnitService;          
            m_AccountChargeService = _AccountChargeService;
            m_DbContext = _DbContext;
        }

        protected AgentClientBaseService _AgentClient;
        private AgentClientBaseService GetAgent(ProductEntity product)
        {
            AgentClientBaseService agent=null;
            if (product.GroupNO == "g1")
                agent = new AgentClient1Service(m_HttpClientFactory) { ClientName=product.GroupNO};
            if (product.GroupNO == "g2")
                agent = new AgentClient2Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g3")
                agent = new AgentClient3Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g4")
                agent = new AgentClient4Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g5")
                agent = new AgentClient5Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g6")
                agent = new AgentClient6Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g7")
                agent = new AgentClient7Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g8")
                agent = new AgentClient8Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g9")
                agent = new AgentClient9Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g10")
                agent = new AgentClient10Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g11")
                agent = new AgentClient11Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g12")
                agent = new AgentClient12Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g13")
                agent = new AgentClient13Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g14")
                agent = new AgentClient14Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g15")
                agent = new AgentClient15Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g16")
                agent = new AgentClient16Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g17")
                agent = new AgentClient17Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g18")
                agent = new AgentClient18Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            if (product.GroupNO == "g19")
                agent = new AgentClient19Service(m_HttpClientFactory) { ClientName = product.GroupNO };
            agent.Product = product;
            return agent;
        }
        public async Task RefrushAllStatus()
        {
            var products = await m_ProductService.Query(false).OrderBy(m=>m.Sort).ToListAsync();

            await products.ForEachAsync(async m =>
            {
              //  if (m.GroupNO == "g6")
                    await RefrushStatus(m);
            });
        }


        public virtual async Task RefrushStatus(ProductEntity product)
        {
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            int status = await agent.RefrushStatus();      
            if (product.Status != status)
            {
                product.UpdateTime = DateTime.Now;
                product.Status = status;
                await m_ProductService.Update(product);
            }
            if (product.Status == 0)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine($"{product.Name}:离线");
                Console.ResetColor();
            }               
        }
        public virtual async Task<(byte[], string)> GetCode(int productId)
        {
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            return await agent.GetCode();
        }
        public virtual async Task<ApiResult> Login(AgentLoginRequest request)
        {
            var product = await m_ProductService.GetById(request.ProductId);
            product.Token = request.Key;
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            request.Account = product.Account;
            request.Pwd = product.Pwd;
            var ret = await agent.Login(request);
            if (ret.Code == ResultCode.C_SUCCESS)
            {
                product.Status = 1;
                product.Token = ret.Data.ToString();
                await m_ProductService.Update(product);
            }
            return ret;
        }
        public virtual async Task<ApiResult<List<OriginAccountModel>>> GetOriginAccounts(List<ProductAccountEntity> accountList)
        {
            var retList = new List<OriginAccountModel>();          
            foreach (var item in accountList)
            {
                var product = await m_ProductService.GetById(item.ProductId);
                var agent = GetAgent(product);
                agent.Init(product.BaseUrl, product.Token);
                var account = item.Account;
                // if (product.GroupNO == "g7") account = item.Raw;
                var ret = await agent.GetAccountInfo(account);
                if (ret.Code == ResultCode.C_SUCCESS)
                    retList.Add(ret.Data as OriginAccountModel);
            }
            return new ApiResult<List<OriginAccountModel>>(retList);
        }

        public virtual async Task<ApiResult<OriginAccountModel>> GetOriginAccountInfo(int productId, string account, string pwd = "")
        {
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            // if (product.GroupNO == "g7")
            // {
            //     var accountInfo = await GetProductAccount(productId, account);
            //     if (accountInfo != null && accountInfo.Raw.Has())
            //         account = accountInfo.Raw;
            // }
            var ret = await agent.GetAccountInfo(account);
            if (ret.Code != ResultCode.C_SUCCESS && product.Id!=17&& product.Id!=13) return new ApiResult<OriginAccountModel>(ResultCode.C_NOT_EXISTS_ERROR, "账号不存在");
            if (pwd.Has()&&ret.Data.Pwd != pwd && product.Id!=17&& product.Id!=13)
                return new ApiResult<OriginAccountModel>(ResultCode.C_NOT_EXISTS_ERROR, "密码不正确");
            return ret;
        }

        public virtual async Task<List<OriginAccountModel>> GetOriginAccountInfo(int productId, List<string> accounts)
        {
            var list = new List<OriginAccountModel>();
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            foreach (var item in accounts)
            {
                var account = item;
                // if (product.GroupNO == "g7")
                // {
                //     var accountInfo = await GetProductAccount(productId, item);
                //     if (accountInfo != null && accountInfo.Raw.Has())
                //         account = accountInfo.Raw;
                // }
                var ret = await agent.GetAccountInfo(account);
                if (ret.Code == ResultCode.C_SUCCESS)
                {
                    list.Add(ret.Data);
                }
            }
            return list;
        }

        /// <summary>
        /// 新开
        /// </summary>
        /// <param name="packageId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public virtual async Task<ApiResult> NewAccount(int orderId, int packageId, string account, string pwd, int connCount = 1, int accountType = 1,int payCount = 1)
        {          
            ApiResult flagResult = new ApiResult(ResultCode.C_SUCCESS);
            var package = await m_ProductPackageService.GetById(packageId);
            var product = await m_ProductService.GetById(package.ProductId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);

            if (package.PackageType == PackageType.Base)
            {              
                var ret = await agent.NewAccount(package.OriginKey, account, pwd, connCount, accountType,payCount);
                //var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
                var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
                await m_AccountChargeService.RecordNew(package, orderId, product.GroupNO, account, pwd, accountType, connCount, status);
                return ret;
            }
            else
            {
                var basePackages = await m_ProductPackageService.GetBasePackages(packageId);
                var firstPackage = basePackages.FirstOrDefault();
                basePackages.Remove(firstPackage);
                if (firstPackage.Count > 1)
                {
                    firstPackage.Count--;
                    basePackages.Insert(0, firstPackage);
                }              
                var ret = await agent.NewAccount(firstPackage.Package.OriginKey, account, pwd, connCount, accountType,payCount);
                //var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
                var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
                await m_AccountChargeService.RecordNew(firstPackage.Package, orderId, product.GroupNO, account, pwd, accountType, connCount, status);

                if (ret.Code != ResultCode.C_SUCCESS)
                    flagResult = ret;

                foreach (var item in basePackages)
                {
                    for (var j = 0; j < item.Count; j++)
                    {                      
                        ret = await agent.NewReAccount(item.Package.OriginKey, account, connCount);
                       // ret = new ApiResult(ResultCode.C_INVALID_ERROR);
                        status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
                        await m_AccountChargeService.RecordReNew(item.Package, orderId, product.GroupNO, account, connCount, status);
                        if (ret.Code != ResultCode.C_SUCCESS)
                            flagResult = ret;
                    }
                }
                return flagResult;
            }
        }


        /// <summary>
        /// 续费
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public virtual async Task<ApiResult> ReNewAccount(int orderId, int packageId, string account, int connCount,int payCount = 1)
        {           
            var package = await m_ProductPackageService.GetById(packageId);
            var product = await m_ProductService.GetById(package.ProductId);
            // if (product.GroupNO == "g7")
            // {
            //     var accountInfo = await GetProductAccount(package.ProductId, account);
            //     if (accountInfo != null && accountInfo.Raw.Has())
            //         account = accountInfo.Raw;
            // }
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            ApiResult flagResult = new ApiResult(ResultCode.C_SUCCESS);
            if (package.PackageType == PackageType.Base)
            {               
                var ret = await agent.NewReAccount(package.OriginKey, account, connCount,payCount);
               // var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
                var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
                await m_AccountChargeService.RecordReNew(package, orderId, product.GroupNO, account, connCount, status);
                return ret;
            }
            else
            {
                var basePackages = await m_ProductPackageService.GetBasePackages(packageId);
                foreach (var basePackage in basePackages)
                {
                    for (var j = 0; j < basePackage.Count; j++)
                    {                     
                        var ret = await agent.NewReAccount(basePackage.Package.OriginKey, account, connCount,payCount);
                        //var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
                        var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;
                        await m_AccountChargeService.RecordReNew(basePackage.Package, orderId, product.GroupNO, account, connCount, status);
                        if (status == ChargeStatus.Faild) flagResult = ret;
                    }
                }
                return flagResult;
            }
        }
        /// <summary>
        /// 删除账号
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public virtual bool DeleteAccount(int productId, string account)
        {
            return true;
        }
        /// <summary>
        /// 修改账号密码
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public virtual async Task<bool> UpdateAccountPwd(int productId, string account, string pwd)
        {
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            // if (product.GroupNO == "g7")
            // {
            //     var accountInfo = await GetProductAccount(productId, account);
            //     if (accountInfo != null && accountInfo.Raw.Has())
            //         agent.Raw = accountInfo.Raw;
            // }
            return await agent.UpdateAccountPwd(account, pwd);
        }
        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="packageId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public virtual async Task<ApiResult> Refund(ProductPackageEntity package, ProductAccountEntity accountInfo)
        {          
            var product = await m_ProductService.GetById(package.ProductId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            var account = accountInfo.Account;
            // if (product.GroupNO == "g7")
            // {               
            //     if (accountInfo != null && accountInfo.Raw.Has())
            //         account = accountInfo.Raw;
            // }
            var flag = await agent.Refund(account, package.OriginKey, accountInfo.RestDay);
            return flag;
        }
        /// <summary>
        /// 是否在线
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public virtual async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(int productId, string account)
        {
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            return await agent.OnLine(account);
        }
        /// <summary>
        /// 踢号
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public virtual async Task<bool> KillOut(int productId, string id)
        {
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            return await agent.KillOut(id);
        }

        /// <summary>
        /// 是否存在
        /// </summary>      
        /// <param name="account"></param>
        /// <returns></returns>
        public async Task<bool> Exist(int productId, string account)
        {
            var product = await m_ProductService.GetById(productId);
            var agent = GetAgent(product);
            agent.Init(product.BaseUrl, product.Token);
            return await agent.Exist(account);
        }

        public async Task FaildTry()
        {
            var records = await m_AccountChargeService.GetFaildRecord();

            foreach (var chargeEntity in records)
            {
                if (chargeEntity.Status != ChargeStatus.Faild)
                {
                    continue;
                }
                if (chargeEntity.TryTimes > 3)
                {
                    chargeEntity.Status = ChargeStatus.Outtime;
                    chargeEntity.UpdateTime = DateTime.Now;
                    await m_AccountChargeService.Update(chargeEntity);
                    continue;
                }
                var product = await m_ProductService.GetById(chargeEntity.ProductId);
                var agent = GetAgent(product);
                agent.Init(product.BaseUrl, product.Token);
                if (chargeEntity.OperationType == ChargeOperationType.New)
                {                  
                    var ret = await agent.NewAccount(chargeEntity.PackageOriginKey, chargeEntity.Account, chargeEntity.Pwd, chargeEntity.ConnectCount, chargeEntity.AccountType);                 
                    var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;

                    chargeEntity.Status = status;
                    chargeEntity.TryTimes++;
                    chargeEntity.UpdateTime = DateTime.Now;
                    await m_AccountChargeService.Update(chargeEntity);
                }else if(chargeEntity.OperationType == ChargeOperationType.ReNew)
                {                  
                    var ret = await agent.NewReAccount(chargeEntity.PackageOriginKey, chargeEntity.Account, chargeEntity.ConnectCount);
                   // var ret = new ApiResult(ResultCode.C_INVALID_ERROR);
                    var status = ret.Code == ResultCode.C_SUCCESS ? ChargeStatus.Ok : ChargeStatus.Faild;

                    chargeEntity.Status = status;
                    chargeEntity.TryTimes++;
                    chargeEntity.UpdateTime = DateTime.Now;
                    await m_AccountChargeService.Update(chargeEntity);
                }
            }
        }


        protected async Task<ProductAccountEntity> GetProductAccount(int productId, string account)
        {
            return await m_DbContext.Set<ProductAccountEntity>().FirstOrDefaultAsync(m => m.ProductId == productId && m.Account == account);
        }                
    }
}
