using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Common.Standard;
using XYY.Data.Standard.DingTalk;
using XYY.Model.Standard.DingTalk;

namespace XYY.Service.Standard.Finance
{
    public interface IDingTalk_ReimbursementService
    {
        Task<string> DingTalkStartProcessEvent(string code);
        Task ApplySubmit(string code);
        Task Refuse(string code);
        Task Cancel(string code);

        Task<PageResult<DingTalk_Reimbursement>> QueryPage(QueryModel qm);
        Task<List<DingTalk_ReimbursementOptions>> GetOptionsByType(int OptionType);
        Task<List<DingTalk_ReimbursementDetail>> GetReimbursementDetails(int ReimbursementId);
        Task<List<CascadeChoice>> GetReimbursementCascadeChoice();
    }
    public class DingTalk_ReimbursementService : IDingTalk_ReimbursementService
    {
        private readonly IDingDingBaseService _dingDingBaseService;
        private readonly IDingTalk_ReimbursementRepository _repository;
        public DingTalk_ReimbursementService(IDingTalk_ReimbursementRepository repository, IDingDingBaseService dingDingBaseService)
        {
            _repository = repository;
            _dingDingBaseService = dingDingBaseService;
        }
        #region 创建申请
        /// <summary>
        /// 获取任务详情
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        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);
                taskid = long.Parse(rsp.ProcessInstance.Tasks[0].Taskid);
                //数据转换
                var data = await ConvertReimbursement(rsp, user, code);
                List<DingTalk_ReimbursementDetail> detailData = data.details;
                //数据写入
                var longId = await _repository.InsertAsync(data);
                await _repository.insertDetail(Convert.ToInt32(longId), detailData);

                return "成功";
            }
            catch (Exception e)
            {
                string message = e.Message;
                if (taskid > 0)
                    message = await _dingDingBaseService.RefuseDingTalk(code, e.Message, taskid);
                return message;
            }
        }

        private async Task<DingTalk_Reimbursement> ConvertReimbursement(OapiProcessinstanceGetResponse rsp, XYY.Model.Standard.User_Info user, string code)
        {
            var data = new DingTalk_Reimbursement()
            {
                ProcessCode = code,
                originator_dept_id = rsp.ProcessInstance.OriginatorDeptId,
                originator_dept_name = rsp.ProcessInstance.OriginatorDeptName,
                originator_userid = rsp.ProcessInstance.OriginatorUserid,
                wms_userid = user.Id,
                wms_userName = user.NickName,
                title = rsp.ProcessInstance.Title,
                business_id = rsp.ProcessInstance.BusinessId,
                Status = XYY.Model.Standard.ObjectApplyEnum.待审,
                startTime = Convert.ToDateTime(rsp.ProcessInstance.CreateTime),
                finish_time = !string.IsNullOrEmpty(rsp.ProcessInstance.FinishTime) ? Convert.ToDateTime(rsp.ProcessInstance.FinishTime) : null,
            };
            List<DingTalk_ReimbursementDetail> details = new List<DingTalk_ReimbursementDetail>();
            foreach (var item in rsp.ProcessInstance.FormComponentValues)
            {
                if (item.Name == "表格")
                {
                    var value_value = JsonConvert.DeserializeObject<List<form_value_tablefieid>>(item.Value);
                    if (value_value.Count == 0) { continue; }
                    foreach (var value in value_value)
                    {
                        DingTalk_ReimbursementDetail detail = new DingTalk_ReimbursementDetail();
                        foreach (var ext in value.rowValue)
                        {
                            if (ext.label == "报销所属")
                            {
                                detail.companyDId = ext.extendValue.id;
                                detail.companyDName = ext.extendValue.name;
                            }
                            else if (ext.label == "报销类别")
                            {
                                var ids = ext.extendValue.fullIdPath.Split('/');
                                var names = ext.extendValue.fullNamePath.Split('/');
                                detail.Categories1_Id = Convert.ToInt32(ids[0]);
                                detail.Categories1_Name = names[0];
                                detail.Categories2_Id = ids.Count() > 1 ? Convert.ToInt32(ids[1]) : Convert.ToInt32(ids[0]);
                                detail.Categories2_Name = names.Count() > 1 ? names[1] : names[0];
                            }
                            else if (ext.label == "报销金额（元）")
                            {
                                detail.ReimbursementAmount = Convert.ToDecimal(ext.value);
                            }
                            else if (ext.label == "摘要")
                            {
                                detail.Remark = ext.value.ToString();
                            }
                            else if (ext.label == "图片")
                            {
                                var urls = JsonConvert.DeserializeObject<List<string>>(ext.value.ToString());
                                if (urls != null && urls.Count() > 0)
                                    detail.ImageUrl = string.Join(',', urls);
                            }
                            else if (ext.label == "电子发票")
                            {
                                //电子发票不做处理，不清楚格式
                                //var urls = JsonConvert.DeserializeObject<List<string>>(ext.value.ToString());
                                //if (urls != null && urls.Count() > 0)
                                //    detail.InvoiceUrl = string.Join(',', urls);
                            }
                        }
                        details.Add(detail);
                    }
                }
            }

            data.ReimbursementAmount = details.Sum(x => x.ReimbursementAmount);
            data.details = details;
            await InsReimbursementOptions(details);
            return data;
        }
        /// <summary>
        /// 8月数据导入方法
        /// 仅用于8月旧数据同步
        /// </summary>
        /// <returns></returns>
        private async Task<DingTalk_Reimbursement> ConvertReimbursement8(OapiProcessinstanceGetResponse rsp, XYY.Model.Standard.User_Info user, string code)
        {
            var Status = XYY.Model.Standard.ObjectApplyEnum.待审;
            if (rsp.ProcessInstance.Result == "agree") { Status = XYY.Model.Standard.ObjectApplyEnum.通过; }
            else if (rsp.ProcessInstance.Result == "refuse") { Status = XYY.Model.Standard.ObjectApplyEnum.驳回; }
            else if (rsp.ProcessInstance.Status == "CANCELED") { Status = XYY.Model.Standard.ObjectApplyEnum.撤销; }

            var data = new DingTalk_Reimbursement()
            {
                ProcessCode = code,
                originator_dept_id = rsp.ProcessInstance.OriginatorDeptId,
                originator_dept_name = rsp.ProcessInstance.OriginatorDeptName,
                originator_userid = rsp.ProcessInstance.OriginatorUserid,
                wms_userid = user.Id,
                wms_userName = user.NickName,
                title = rsp.ProcessInstance.Title,
                business_id = rsp.ProcessInstance.BusinessId,
                Status = Status,
                startTime = Convert.ToDateTime(rsp.ProcessInstance.CreateTime),
                finish_time = !string.IsNullOrEmpty(rsp.ProcessInstance.FinishTime) ? Convert.ToDateTime(rsp.ProcessInstance.FinishTime) : null,
            };
            List<DingTalk_ReimbursementDetail> details = new List<DingTalk_ReimbursementDetail>();
            foreach (var item in rsp.ProcessInstance.FormComponentValues)
            {
                List<DingTalk_ReimbursementDetail> tempDetails = new List<DingTalk_ReimbursementDetail>();
                string ImageUrl = string.Empty; string InvoiceUrl = string.Empty;
                if (item.Name == "报销明细")
                {
                    DingTalk_ReimbursementDetail detail = new DingTalk_ReimbursementDetail();
                    var value_value = JsonConvert.DeserializeObject<List<form_value_tablefieid>>(item.Value);
                    if (value_value.Count == 0) { continue; }
                    foreach (var value in value_value)
                    {
                        foreach (var ext in value.rowValue)
                        {
                            if (ext.label == "报销所属")
                            {
                                detail.companyDId = ext.extendValue.id;
                                detail.companyDName = ext.extendValue.name;
                            }
                            else if (ext.label == "报销类别")
                            {
                                var ids = ext.extendValue.fullIdPath.Split("  ");
                                var names = ext.extendValue.fullNamePath.Split("  ");
                                detail.Categories1_Id =0;
                                detail.Categories1_Name = names[0];
                                detail.Categories2_Id = 0;
                                detail.Categories2_Name = names.Count() > 1 ? names[1] : names[0];
                            }
                            else if (ext.label == "报销金额(元)")
                            {
                                detail.ReimbursementAmount = Convert.ToDecimal(ext.value);
                            }
                            else if (ext.label == "费用明细")
                            {
                                detail.Remark = ext.value.ToString();
                            }

                        }
                    }
                    tempDetails.Add(detail);
                }
                else if (item.Name == "图片")
                {
                    var urls = JsonConvert.DeserializeObject<List<string>>(item.Value.ToString());
                    if (urls != null && urls.Count() > 0)
                        ImageUrl = string.Join(',', urls);
                }
                else if (item.Name == "附件")
                {
                    var urls = JsonConvert.DeserializeObject<List<string>>(item.Value.ToString());
                    if (urls != null && urls.Count() > 0)
                        InvoiceUrl = string.Join(',', urls);
                }

                tempDetails.ForEach(x => { x.ImageUrl = ImageUrl;x.InvoiceUrl = InvoiceUrl; });
                details.AddRange(tempDetails);
            }

            data.ReimbursementAmount = details.Sum(x => x.ReimbursementAmount);
            data.details = details;
            await InsReimbursementOptions(details);
            return data;
        }
        private async Task InsReimbursementOptions(List<DingTalk_ReimbursementDetail> details)
        {
            List<DingTalk_ReimbursementOptions> insertOptions = new List<DingTalk_ReimbursementOptions>();
            List<DingTalk_ReimbursementOptions> updateOptions = new List<DingTalk_ReimbursementOptions>();
            //表数据量不大，取全表
            var dbData = await _repository.GetAllReimbursementOptions();
            foreach (var item in details)
            {
                //检测报销所属
                var company = dbData.Where(x => x.DId == item.companyDId && x.OptionType == OptionTypeEnum.company).FirstOrDefault();
                if (insertOptions.Any(x => x.DId == item.companyDId)) { }
                else if (company == null)
                {
                    DingTalk_ReimbursementOptions model = new DingTalk_ReimbursementOptions()
                    {
                        DId = item.companyDId,
                        DName = item.companyDName,
                        OptionType = OptionTypeEnum.company,
                        DParentId = 0,
                        LevelNum = 0,
                    };
                    insertOptions.Add(model);
                }
                else if (company.DName != item.companyDName)
                {
                    company.DName = item.companyDName; company.LevelNum = 0; company.DParentId = 0; updateOptions.Add(company);
                }
                //检测一级菜单
                var level0 = dbData.Where(x => x.DId == item.Categories1_Id && x.OptionType == OptionTypeEnum.category).FirstOrDefault();
                if (insertOptions.Any(x => x.DId == item.Categories1_Id)) { }
                else if (level0 == null)
                {
                    DingTalk_ReimbursementOptions model = new DingTalk_ReimbursementOptions()
                    {
                        DId = item.Categories1_Id ?? 0,
                        DName = item.Categories1_Name,
                        OptionType = OptionTypeEnum.category,
                        DParentId = 0,
                        LevelNum = 0,
                    };
                    insertOptions.Add(model);
                }
                else if (level0.DName != item.Categories1_Name)
                {
                    level0.DName = item.Categories1_Name; level0.LevelNum = 0; level0.DParentId = 0; updateOptions.Add(level0);
                }
                //检测二级菜单 没有二级菜单的时候，会默认写一级菜单的数据
                var level1 = dbData.Where(x => x.DId == item.Categories2_Id && x.OptionType == OptionTypeEnum.category).FirstOrDefault();
                if (insertOptions.Any(x => x.DId == item.Categories2_Id)) { }
                else if (level1 == null)
                {
                    DingTalk_ReimbursementOptions model = new DingTalk_ReimbursementOptions()
                    {
                        DId = item.Categories2_Id ?? 0,
                        DName = item.Categories2_Name,
                        OptionType = OptionTypeEnum.category,
                        DParentId = item.Categories1_Id,
                        LevelNum = 1,
                    };
                    insertOptions.Add(model);
                }
                else if (level1.DName != item.Categories1_Name)
                {
                    level1.DName = item.Categories2_Name; level1.LevelNum = 1; level1.DParentId = item.Categories1_Id; updateOptions.Add(level1);
                }
            }
            if (insertOptions.Count > 0) { await _repository.insertOptions(insertOptions); }
            if (updateOptions.Count > 0) { await _repository.BatchUpdateOptionsEntiy(updateOptions); }
        }
        #endregion

        #region 审核、撤销操作
        /// <summary>
        /// 审核通过
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public async Task ApplySubmit(string code)
        {
            var records = await _repository.QueryAsync(i => i.ProcessCode == code);
            var record = records.FirstOrDefault();
            if (record == null)
            {
                throw new Exception($"不存在审批记录:{code}");
            }
            record.Status = XYY.Model.Standard.ObjectApplyEnum.通过;
            record.finish_time = DateTime.Now;
            await _repository.UpdateAsync(record);
        }
        public async Task Refuse(string code)
        {
            await _repository.UpdateByConditionAsync(i => i.ProcessCode == code, new
            {
                Status = (int)XYY.Model.Standard.ObjectApplyEnum.驳回,
                finish_time = DateTime.Now,
            });
        }
        public async Task Cancel(string code)
        {
            await _repository.UpdateByConditionAsync(i => i.ProcessCode == code, new
            {
                Status = (int)XYY.Model.Standard.ObjectApplyEnum.撤销,
                finish_time = DateTime.Now,
            });
        }
        #endregion

        #region 申请记录查询
        public async Task<PageResult<DingTalk_Reimbursement>> QueryPage(QueryModel qm)
        {
            return await _repository.QueryPage(qm);
        }
        public async Task<List<DingTalk_ReimbursementOptions>> GetOptionsByType(int OptionType)
        {
            return await _repository.GetOptionsByType(OptionType);
        }
        public async Task<List<DingTalk_ReimbursementDetail>> GetReimbursementDetails(int ReimbursementId)
        {
            return await _repository.GetReimbursementDetails(ReimbursementId);
        }
        public async Task<List<CascadeChoice>> GetReimbursementCascadeChoice()
        {
            List<CascadeChoice> cascadeChoices = new List<CascadeChoice>();
            var dbData = await GetOptionsByType((int)OptionTypeEnum.category);
            foreach (var item in dbData.Where(x => x.LevelNum == 0))
            {
                var child = await ConvertToChoice(dbData.Where(x => x.DParentId == item.DId).ToList());
                CascadeChoice model = new CascadeChoice()
                {
                    label = item.DName,
                    value = item.DId,
                    children = child.Count > 0 ? child : new List<Choice>() { new Choice() { label = item.DName, value = item.DId, } },
                };
                cascadeChoices.Add(model);
            }
            return cascadeChoices;
        }
        private async Task<List<Choice>> ConvertToChoice(List<DingTalk_ReimbursementOptions> options)
        {
            List<Choice> choices = new List<Choice>();
            foreach (var item in options)
            {
                choices.Add(new Choice()
                {
                    label = item.DName,
                    value = item.DId,
                });
            }
            return choices;
        }
        #endregion
    }
}
