using XYY.Core.Standard.ExcelHelper.MSExcelHelper;
using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Common.Standard;
using XYY.Core.Standard.Mvc;
using XYY.Data.Standard;
using XYY.Data.Standard.Finance;
using XYY.Model.Standard;
using XYY.Model.Standard.Finance;
using XYY.Service.Standard.Customer;

namespace XYY.Service.Standard.Finance
{
    public interface ICustomerAccountService
    {
        Task<PageResult<View_Finance_Customer_Account>> GetPager(QueryModel querModel);
        Task<long> CreateDefault(AccountTypeEnum enumValue, int customerId);
        /// <summary>
        /// 更新基本信息（逾期收款比例，付款期限天数，授信）
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        Task Update(Finance_Customer_Account account);
        Task<IEnumerable<Finance_Customer_AccountLog>> GetLogs(int Id);
        Task<ApiJsonModel> AddAccountQuotaApply(Finance_Customer_Account_ApplyRecord model);
        Task<PageResult<View_Finance_Customer_Account_ApplyRecord>> GetAccountQuotaPager(QueryModel querModel);
        Task ApplySubmit(ApplySubmitRequest model);
        Task ApplySubmit(string code);
        Task Refuse(string code);
        Task Cancel(string code);
        Task<string> DingTalkStartProcessEvent(string code);
        Task<ApiJsonModel> QuotaReduction(DateTime startTime, DateTime endTime);
        Task<List<ViewCustomerIncome>> QueryCustomerIncome(QueryModel query);
        Task<byte[]> OutCustomerIncome(QueryModel query);
    }

    public class CustomerAccountService : ICustomerAccountService
    {
        IDingDingBaseService dingDingBaseService;
        IFinance_Customer_AccountRepository _accountRepository;
        IFinance_Customer_Account_ApplyRecordRepository _finance_Customer_Account_ApplyRecordRepository;
        ICustomerService _customerService;
        IViewCustomerIncomeRepository _viewCustomerIncomeRepository;
        public CustomerAccountService(
            IFinance_Customer_AccountRepository accountRepository,
            IDingDingBaseService dingDingBaseService,
            IFinance_Customer_Account_ApplyRecordRepository finance_Customer_Account_ApplyRecordRepository,
            ICustomerService customerService, IViewCustomerIncomeRepository viewCustomerIncomeRepository)
        {
            _accountRepository = accountRepository;
            this.dingDingBaseService = dingDingBaseService;
            _finance_Customer_Account_ApplyRecordRepository = finance_Customer_Account_ApplyRecordRepository;
            _customerService = customerService;
            _viewCustomerIncomeRepository = viewCustomerIncomeRepository;
        }
        public async Task<long> CreateDefault(AccountTypeEnum enumValue, int customerId)
        {
            var dbModel = await _accountRepository.QueryAsync(x => x.CustomerId == customerId);
            if (dbModel != null && dbModel.Count() > 0) { return dbModel.FirstOrDefault().Id; }
            Finance_Customer_Account model = new Finance_Customer_Account()
            {
                AccountType = enumValue,
                CustomerId = customerId,
            };
            var Id = await _accountRepository.InsertAsync(model);
            return Id;
        }
        /// <summary>
        /// 基础检验
        /// </summary>
        /// <param name="account"></param>
        private void CheckAccount(Finance_Customer_Account account)
        {
            if (account.OverdueRatio < 0)
                throw new Exception("逾期比例必须为0以上");
            if (account.Quota < 0)
                throw new Exception("授信金额必须为0以上");
            if (account.RepaymentTermDay <= 0)
                throw new Exception("帐期付款天数必须大于0");
        }

        public async Task<string> DingTalkStartProcessEvent(string code)
        {
            long taskid = 0;
            try
            {
                string token = await dingDingBaseService.GetTokenAsCache();
                IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/get");
                OapiProcessinstanceGetRequest req = new OapiProcessinstanceGetRequest();
                req.ProcessInstanceId = code;
                OapiProcessinstanceGetResponse rsp = client.Execute(req, token);
                //获取用户信息
                var user = await dingDingBaseService.GetUserInfo(rsp.ProcessInstance.OriginatorUserid);
                //原始UserId
                var data = new Finance_Customer_Account_ApplyRecord
                {
                    OriginatorUserid = rsp.ProcessInstance.OriginatorUserid,
                    OriginatorDeptId = rsp.ProcessInstance.OriginatorDeptId,
                    CreateUserName = user.NickName,
                    CreateTime = DateTime.Now,
                    ProcessCode = code,
                    ApplyStatus = 1
                };
                var customers = await _customerService.CacheGetAllCustomers();
                taskid = long.Parse(rsp.ProcessInstance.Tasks[0].Taskid);
                foreach (var item in rsp.ProcessInstance.FormComponentValues)
                {
                    if (item.Name == "客户代码")
                    {
                        var customer = customers.FirstOrDefault(x => x.CustomerNumber.Equals(item.Value, StringComparison.OrdinalIgnoreCase));
                        if (customer == null)
                        {
                            throw new Exception($"未找到客户代码为{item.Value}的客户");
                        }
                        data.CustomerId = customer.Id;
                    }
                    else if (item.Name == "生效时间")
                    {
                        data.StartTime = DateTime.Parse(item.Value);
                    }
                    else if (item.Name == "过期时间")
                    {
                        data.EndTime = DateTime.Parse(item.Value);
                    }
                    else if (item.Name == "调整额度（￥）")
                    {
                        data.ApplyValue = decimal.Parse(item.Value);
                    }
                    else if (item.Name == "调整说明")
                    {
                        data.ApplyDec = item.Value;
                    }
                }
                data.Field = "临时额度";
                var apiResult = await AddAccountQuotaApply(data);
                if (!apiResult.success)
                    return apiResult.message;
                //throw new Exception("测试回滚");
                return "成功";
            }
            catch (Exception e)
            {
                string message = e.Message;
                if (taskid > 0)
                    message = await RefuseDingTalk(code, e.Message, taskid);
                return message;
            }
        }

        public async Task<string> RefuseDingTalk(string code, string msg, long taskId)
        {
            string token = await dingDingBaseService.GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/process/instance/execute");
            OapiProcessinstanceExecuteV2Request req = new OapiProcessinstanceExecuteV2Request();
            req.Request_ = new OapiProcessinstanceExecuteV2Request.ExecuteTaskRequestDomain
            {
                ProcessInstanceId = code,
                TaskId = taskId,
                Result = "refuse",
                Remark = msg,
                ActionerUserid = DefaultUserId.UserId
            };
            var rsp = client.Execute(req, token);
            string errorMsg = Newtonsoft.Json.JsonConvert.SerializeObject(rsp);
            return errorMsg ?? "成功";
        }


        /// <summary>
        /// 更新基本信息（逾期收款比例，付款期限天数，授信）
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public async Task Update(Finance_Customer_Account account)
        {
            //CheckAccount(account);

            if (!(await _accountRepository.IsExistsAsync(x => x.CustomerId == account.CustomerId)))
                await _accountRepository.InsertAsync(account);
            else
            {
                var updateAccount = (await _accountRepository.QueryAsync(x => x.CustomerId == account.CustomerId)).First();
                updateAccount.OverdueRatio = account.OverdueRatio;
                updateAccount.RepaymentTermDay = account.RepaymentTermDay;
                updateAccount.Quota = account.Quota;
                updateAccount.Currency = account.Currency;
                await _accountRepository.UpdateAsync(updateAccount);
            }
        }


        public async Task<IEnumerable<Finance_Customer_AccountLog>> GetLogs(int Id)
        {
            var list = await _accountRepository.GetLogs(Id);
            list = list.OrderBy(x => x.CreateTime);
            return list;
        }

        public async Task<PageResult<View_Finance_Customer_Account>> GetPager(QueryModel querModel)
        {
            return await _accountRepository.GetPager(querModel);
        }
        public async Task<ApiJsonModel> AddAccountQuotaApply(Finance_Customer_Account_ApplyRecord model)
        {
            try
            {
                var Id = await _finance_Customer_Account_ApplyRecordRepository.InsertAsync(model);

            }
            catch (Exception ex)
            {
                return ApiJsonModel.Error(ex.Message);
            }
            return ApiJsonModel.OK();
        }
        public async Task<PageResult<View_Finance_Customer_Account_ApplyRecord>> GetAccountQuotaPager(QueryModel querModel)
        {
            return await _finance_Customer_Account_ApplyRecordRepository.GetPager(querModel);
        }
        public async Task ApplySubmit(ApplySubmitRequest model)
        {
            await _finance_Customer_Account_ApplyRecordRepository.ApplySubmit(model);
        }

        public async Task ApplySubmit(string code)
        {
            var records = await _finance_Customer_Account_ApplyRecordRepository.QueryAsync(i => i.ProcessCode == code);

            if (records?.Any() != true)
            {
                throw new Exception($"不存在审批记录:{code}");
            }
            string id = string.Join(",", records.Select(i => i.Id));
            ApplySubmitRequest model = new ApplySubmitRequest
            {
                applyStatu = (int)ObjectApplyEnum.通过,
                Ids = id,
                ReplyDec = ObjectApplyEnum.通过.GetDescription()
            };
            await ApplySubmit(model);
        }
        public async Task<ApiJsonModel> QuotaReduction(DateTime startTime, DateTime endTime)
        {
            try
            {
                var records = await _accountRepository.GetAccountList(startTime, endTime);
                if (records == null || records.Count() < 1) { return ApiJsonModel.OK("无过期数据"); }
                await _accountRepository.QuotaReduction(records.ToList());
                #region 消息发送处理
                var QuotaExpirationIds = records.Where(x => (x.QuotaExpirationId ?? 0) > 0).Select(x => x.QuotaExpirationId ?? 0).ToList();
                var applyRecords = _finance_Customer_Account_ApplyRecordRepository.ApplyListByIds(QuotaExpirationIds).Result.ToList();
                foreach (var item in applyRecords)
                {
                    try
                    {
                        var ddModel = new
                        {
                            msgtype = "text",
                            text =
                           new
                           {
                               content = $"临时授信额度已到期，已将客户【{item.CustomerAccountName}】额度还原为基础额度，请知悉！"
                           }
                        };
                        await dingDingBaseService.SendMessage(item.OriginatorUserid, ddModel);
                    }
                    catch (Exception ex)
                    {
                        continue;//发送信息的异常不做处理
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                return ApiJsonModel.Error(ex.Message);
            }
            return ApiJsonModel.OK();
        }

        public async Task Refuse(string code)
        {
            await UpdateRecordStatus(code, ObjectApplyEnum.驳回);
        }

        private async Task UpdateRecordStatus(string code, ObjectApplyEnum status)
        {
            int statusVal = (int)status;
            string desc = status.GetDescription();
            await _finance_Customer_Account_ApplyRecordRepository.UpdateByConditionAsync(i => i.ProcessCode == code, new { ApplyStatus = statusVal, ReplyDec = desc });
        }

        public async Task Cancel(string code)
        {
            await UpdateRecordStatus(code, ObjectApplyEnum.撤销);
        }

        public async Task<byte[]> OutCustomerIncome(QueryModel query)
        {
            var list = await QueryCustomerIncome(query);
            MSExcelHelper excelHelper = new MSExcelHelper();
            return excelHelper.OutDataAsByte<CustomerIncomeMapping, ViewCustomerIncome>(list);

        }

        public class CustomerIncomeMapping : MSExcelClassMapping<ViewCustomerIncome>
        {
            public CustomerIncomeMapping()
            {
                Map(x => x.结算公司).Name("结算公司");
                Map(x => x.客户).Name("客户");
                Map(x => x.业务员).Name("业务员");
                Map(x => x.收货票数).Name("收货票数");
                Map(x => x.结算金额).Name("结算金额");
                Map(x => x.渠道).Name("渠道");
            }
        }

        public async Task<List<ViewCustomerIncome>> QueryCustomerIncome(QueryModel query)
        {
            string where = "";
            string group = "";
            string select = "";
            if (query != null)
            {
                if (query.GroupBy != null)
                {

                    var groupByUser = query.GroupBy.Any(x => x.Equals("Customer", StringComparison.OrdinalIgnoreCase));
                    if (groupByUser)
                    {
                        group += "isnull(c.Abbreviation, c.CompanyName),";
                        select += "isnull(c.Abbreviation, c.CompanyName)客户,";
                    }
                    var groupByChannel = query.GroupBy.Any(x => x.Equals("Channel", StringComparison.OrdinalIgnoreCase));
                    if (groupByChannel)
                    {
                        group += " f.Name,";
                        select += "f.Name[渠道],";
                    }
                }
                if (query.QueryParamer != null)
                {
                    var SalesmanUserIdParamer = query.QueryParamer.FirstOrDefault(x => x.Filed == "SalesmanUserId");
                    if (SalesmanUserIdParamer != null)
                        SalesmanUserIdParamer.Filed = "c.SalesmanUserId";
                    where = _viewCustomerIncomeRepository.GetWhere(query.QueryParamer);
                }

            }


            string sql = $@"select 
                             {select} e.CompanyName[结算公司],d.NickName 业务员,
                             sum(isnull(a.OPCFreight, 0))+sum(isnull(a.AttachFee, 0)) + sum(isnull(a.EUTariff, 0))[结算金额],count(0)[收货票数] from Order_Fee(nolock)a
                                                                                                                                        join Order_Order(nolock)b on a.OrderId = b.Id
     
                                 join User_Customer(nolock)c on c.id = b.CustomerId     
                                 join User_Info(nolock)d on c.SalesmanUserId = d.Id     
                                 join User_Customer(nolock)e on e.id = c.BranchCompanyId
                                 left join logistics_channel(nolock)h on h.Id = b.CreateOrderChannelId
                                 left join logistics_Public(nolock)f on f.Code=h.PublicCode
                                 where  c.Id not in(
                                223, 227, 426) 
                                and OrderStatus in (2, 3)
                                {where}
                            group by {group} d.NickName,e.CompanyName
                              ";


            sql = sql.Replace("@where", where);
            return (await _viewCustomerIncomeRepository.QueryBySqlAsync(sql)).OrderByDescending(x => x.结算金额).ToList();
        }
    }
}
