using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using RB_MES_API.Context;
using RB_MES_API.Models;
using RB_MES_API.Models.Cloud;
using RB_MES_API.Models.Pangu;
using RB_MES_APICore.Models;
using System.Data;
using System.Reflection;
using RB_MES_API.Controllers.Cloud;
using System.Threading;
using Kingdee.CDP.WebApi.SDK;

namespace RB_MES_API.Controllers
{
    public sealed class PushBackgroundService : BackgroundService
    {
        private readonly Task _completedTask = Task.CompletedTask;
        private List<Timer> _timer = new List<Timer>();
        private readonly IServiceScopeFactory _serviceScopeFactory;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceScopeFactory"></param>
        public PushBackgroundService(IServiceScopeFactory serviceScopeFactory)
        {
            _serviceScopeFactory = serviceScopeFactory;
        }

        /// <summary>
        /// 
        /// </summary>
        public class ClientRequestStr
        {
            /// <summary>
            /// 从沃比服务器取回来的加密字符串
            /// </summary>
            public string token { get; set; } = string.Empty;
            /// <summary>
            /// 客户基本资料的信用代码
            /// </summary>
            public string FKey { get; set; } = string.Empty;
            /// <summary>
            /// 组织机构：软件34，科技35
            /// </summary>
            public string organization { get; set; } = "34";
            /// <summary>
            /// 合同号
            /// </summary>
            public string contractno { get; set; } = "230523";
        }

        /// <summary>
        /// 执行异步定时器
        /// </summary>
        public async void DoTimerWorkAsyn()
        {
            try
            {
                string v = LocalStaticRequest.GetSystemProfile(1, "AutoPushTask");

                int.TryParse(v, out int at);

                if (at > 0)
                {
                    //只要FTimer > 0的接口都有一个属于自己的定时器！
                    using var scope = _serviceScopeFactory.CreateScope();
                    IShareController myScopedService = scope.ServiceProvider.GetRequiredService<IShareController>();
                    List<ApiHostService> systimeds = await myScopedService.GetAPIList<ApiHostService>();
                    scope.Dispose();
                    if (systimeds == null) { return; }
                    var sys = from a in systimeds
                              select new
                              {
                                  worktime = a.FTimer,
                                  name = a.FDocType
                              };
                    foreach (var item in sys)
                    {
                        _timer.Add(new Timer(DoWork, item.name, TimeSpan.Zero, TimeSpan.FromMinutes(item.worktime)));
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(string.Format("PushBackgroundService的DoTimerWorkAsyn发生错误：{0}", ex.Message));
            }
        }
        /// <summary>
        /// 优先加载系统必须的静态数据
        /// </summary>
        private void LoadLocalStaticRequest()
        {
            try
            {
                //如果缓存中不存在，就从数据库里取出来再放进缓存
                List<SystemProfile> sys = CacheHelper.GetCache<List<SystemProfile>>("sys");
                if (sys == null)
                {
                    using var scope = _serviceScopeFactory.CreateScope();
                    RBContext myScopedService = scope.ServiceProvider.GetRequiredService<RBContext>();
                    //先初始化全局变量
                    sys = myScopedService.r_SystemProfiles!.AsNoTracking().ToList();
                    if (sys.Any())
                    {
                        CacheHelper.Set_AbsluteExpire("sys", sys);
                    }
                    scope.Dispose();
                }
                //无论是否推送，静态全局设置应该首先加载
                LocalStaticRequest.sysprofile = sys;
                //string svurl = LocalStaticRequest.GetSystemProfile(4, "TokenUrl");
                string orgid = LocalStaticRequest.GetSystemProfile(2, "DefaultORGID");
                string orgno = LocalStaticRequest.GetSystemProfile(2, "DefaultORG");
                LocalStaticRequest.DefaultOrgID = string.IsNullOrEmpty(orgid) ? 1 : int.Parse(orgid);
                LocalStaticRequest.DefaultOrg = string.IsNullOrEmpty(orgno) ? "100" : orgno;
                string tokenstr = LocalStaticRequest.GetSystemProfile(4, "TokenPWD");    //客户基本资料的信用代码
                string acctid = ApiSettingsHelper.GetConfig("X-KDApi-AcctID");
                string appid = ApiSettingsHelper.GetConfig("X-KDApi-AppID");
                string sppsec = ApiSettingsHelper.GetConfig("X-KDApi-AppSec");
                string apiurl = ApiSettingsHelper.GetConfig("X-KDApi-ServerUrl");
                string usname = ApiSettingsHelper.GetConfig("X-KDApi-UserName");
                int lcid = 0;
                int.TryParse(ApiSettingsHelper.GetConfig("X-KDApi-LCID"), out lcid);
                LocalStaticRequest.cloudApi.InitClient(acctid, appid, sppsec, usname, lcid, orgno, apiurl);
            }
            catch (Exception ex)
            {
                //如果金蝶Cloud登录失败，就会发生异常，可能导致程序崩溃...
                string msg = ex.Message;
                LogHelper.WriteLog(string.Format("PushBackgroundService的LoadHostFunctionAsync发生错误：{0}", msg));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        private async void AddUnitCache(object state)
        {
            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                IKDCloudHttpClient myScopedService = scope.ServiceProvider.GetRequiredService<IKDCloudHttpClient>();
                string messstr = string.Empty;
                string fileds = "FUNITID,FNumber,FName,FIsBaseUnit,FPrecision,FDocumentStatus,FForbidStatus,FConvertDenominator,FConvertNumerator,FRoundType";
                BillQuery queryJson = new BillQuery()
                {
                    FieldKeys = fileds,
                    FormId = "BD_UNIT",
                    FilterString = "FDOCUMENTSTATUS='C' AND FFORBIDSTATUS='A'"
                };
                //从云星空查询
                string result = myScopedService.SDKBillQuery(queryJson);
                if (myScopedService.SDKBillQueryStatus(result))
                {
                    IShareController myScopedService1 = scope.ServiceProvider.GetRequiredService<IShareController>();
                    List<BD_UNIT> units = myScopedService1.GetNewObjForChild<BD_UNIT>(fileds, result, ref messstr);
                    if (units.Count > 0)
                    {
                        CacheHelper.Set_AbsluteExpire("BD_UNIT", units);
                    }
                }
                scope.Dispose();
            }
            catch (Exception e)
            {
                LogHelper.WriteLog(string.Format("PushBackgroundService的AddUnitCache发生错误：{0}", e.Message));
            }
        }
        private void DoWork(object state)
        {
            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                IShareController myScopedService = scope.ServiceProvider.GetRequiredService<IShareController>();
                List<CloudBillQuery> queryJsons = myScopedService.GetAPIList<CloudBillQuery>().Result;
                scope.Dispose();
                var clouds = queryJsons.Where(s => s.GetFormID.FDocType == state.ToString()).ToList();
                if (clouds.Count > 0)
                {
                    new TaskFactory().StartNew(() =>
                    {
                        CloudBillQuery query = clouds.FirstOrDefault();
                        Type type = this.GetType();
                        MethodInfo? methodInfo = type.GetMethod(query.GetFormID.FActionName);
                        if (methodInfo != null)
                        {
                            object[] para = new object[] { query.GetFormID.FID, query.GetFormID.functions.FUrl };

                            methodInfo.Invoke(this, para);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(string.Format("PushBackgroundService的BackgroundServiceWork发生错误：{0}", ex.Message));
            }
        }
        /// <summary>
        /// 将自定义SQL查询结果推送给MES
        /// </summary>
        /// <param name="formtypeid"></param>
        /// <param name="url"></param>
        public void GetSelfDBbaseAsync(int formtypeid, string url)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            IShareController myScopedService = scope.ServiceProvider.GetRequiredService<IShareController>();
            IChiledSelect myChiledSelect = scope.ServiceProvider.GetRequiredService<IChiledSelect>();
            string result = myChiledSelect.GetCustomRequestTBAsync(formtypeid).Result;
            List<CloudBillQuery> query = myScopedService.GetAPIList<CloudBillQuery>().Result;
            if (query.Count == 0) { scope.Dispose(); return; };
            string doctype = query.Find(s => s.FFormIDTypeID == formtypeid).GetFormID.FDocType;
            if (string.IsNullOrEmpty(result)) { scope.Dispose(); return; };
            try
            {
                JArray array = (JArray)JsonConvert.DeserializeObject(result);
                if (array == null || array.Count == 0) { scope.Dispose(); return; };
                PanguPostBill mes = new PanguPostBill()
                {
                    DocType = doctype,
                    DataSet = myScopedService.GetClassList(array)
                };
                string json = JsonConvert.SerializeObject(mes);
                //推送给MES
                IKDCloudHttpClient myhttpclient = scope.ServiceProvider.GetRequiredService<IKDCloudHttpClient>();
                PanguBreakJson mesjson = myhttpclient.PushMesData(json).Result;
                if (mesjson.Status)
                {
                    LogHelper.WriteLog(string.Format("推送【{0}】成功：{1}", doctype, json), doctype);
                }
                else
                {
                    LogHelper.WriteLog(string.Format("PushBackgroundService的GetSelfDBbaseAsync方法推送【{0}】失败：{1}\n原始数据：{2}", doctype, mesjson.Message, json), doctype);
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(string.Format("PushBackgroundService推送【{0}】动态GetSelfDBbaseAsync方法出错：{1}", doctype, ex.Message), doctype);
            }
            finally { if (scope != null) scope.Dispose(); }
        }
        /// <summary>
        /// 查询Cloud表单。
        /// </summary>
        /// <param name="formtypeid"></param>
        /// <param name="url"></param>
        public async void GetBDbase(int formtypeid, string url)
        {
            string reason = string.Empty;
            using var scope = _serviceScopeFactory.CreateScope();
            IShareController myScopedService = scope.ServiceProvider.GetRequiredService<IShareController>();
            IKDCloudHttpClient myScopedService1 = scope.ServiceProvider.GetRequiredService<IKDCloudHttpClient>();
            List<CloudBillQuery> queryJsons = await myScopedService.GetAPIList<CloudBillQuery>();
            if (queryJsons.Count == 0)
            {
                LogHelper.WriteLog("PushBackgroundService的GetBDbase方法_shareController.GetAPIList<CloudBillQuery>()缓存过期");
            }
            else
            {
                var formtype = queryJsons.Where(s => s.GetFormID.FID == formtypeid).FirstOrDefault()!.GetFormID;
                int fid = formtype.FFunctionID;
                string doctype = formtype.FDocType;
                var queryJson = from a in queryJsons.Where(s => s.GetFormID.FID == formtypeid)
                                select new BillQuery
                                {
                                    FieldKeys = a.FFieldKeys.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg),
                                    FormId = a.GetFormID.FDBName,
                                    FilterString = a.FFiledString.Replace("GETDATE", DateTime.Now.ToShortDateString()).Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg),
                                    Limit = a.FLimit,
                                    OrderString = a.FOrderString,
                                    StartRow = a.FStartRow,
                                    SubSystemId = a.FSubSystemID,
                                    TopRowCount = a.FTopRowCount
                                };
                if (queryJson.Any())
                {
                    try
                    {
                        string result = myScopedService1.SDKBillQuery(queryJson.FirstOrDefault());
                        if (myScopedService1.SDKBillQueryStatus(result))
                        {
                            string fileds = queryJson.FirstOrDefault()!.FieldKeys!;
                            DataTable dt = myScopedService.JsonConvertDatatable(fileds, result, ref reason);
                            if (!string.IsNullOrEmpty(reason)) { goto EBread; }
                            if (dt.Rows.Count > 0)
                            {
                                List<Dictionary<string, object>> dic = GetClassList(fid, doctype, dt);
                                if (dic.Any())
                                {
                                    PanguPostBill mes = new PanguPostBill()
                                    {
                                        DocType = doctype,
                                        DataSet = dic
                                    };
                                    string json = JsonConvert.SerializeObject(mes);
                                    //推送给MES
                                    IKDCloudHttpClient myhttpclient = scope.ServiceProvider.GetRequiredService<IKDCloudHttpClient>();
                                    PanguBreakJson mesjson = await myhttpclient.PushMesData(json);
                                    if (mesjson.Status)
                                    {
                                        reason = string.Format("推送【{0}】成功：{1}", doctype, json);
                                    }
                                    else
                                    {
                                        reason = string.Format("PushBackgroundService的GetBDbase方法推送【{0}】失败：{1}\r原始数据：{2}", doctype, mesjson.Message, json);
                                    }
                                }
                                else
                                {
                                    reason = string.Format("PushBackgroundService的GetBDbase方法推送【{0}】失败：!GetClassList(fid, doctype, dt)Any()：{1}}", doctype, result);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        reason = string.Format("PushBackgroundService的GetBDbase方法推送【{0}】过程中发生错误：{1}", doctype, ex.Message);
                    }
                }
            EBread:
                if (!string.IsNullOrEmpty(reason)) { LogHelper.WriteLog(reason, doctype); }
            }
            scope.Dispose();
        }

        private List<Dictionary<string, object>> GetClassList(int fid, string decname, DataTable table)
        {
            using var scope = _serviceScopeFactory.CreateScope();
            IShareController myScopedService = scope.ServiceProvider.GetRequiredService<IShareController>();
            List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
            List<SelectClumnConvert> scc = myScopedService.GetAPIList<SelectClumnConvert>().Result;
            scope.Dispose();
            scc = scc.Where(s => s.FFunctionID == fid && s.FDesTableName.Equals(decname)).ToList();
            if (scc.Any())
            {
                foreach (DataRow row in table.Rows)
                {
                    Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
                    foreach (SelectClumnConvert clumnConvert in scc)
                    {
                        string oldname = clumnConvert.FSourceName;
                        if (table.Columns.Contains(oldname))
                        {
                            string newname = clumnConvert.FDesName;
                            keyValuePairs.Add(newname, row[oldname].ToString()!);
                        }
                    }
                    list.Add(keyValuePairs);
                }
            }
            return list;
        }

        /// <inheritdoc/>
        public override Task StopAsync(CancellationToken cancellationToken)
        {
            //t调用 StopAsync时触发cancellationToken改变
            DisposeAsync();
            return _completedTask;
        }
        /// <inheritdoc/>

        public ValueTask DisposeAsync()
        {
            foreach (var item in _timer)
            {
                item.DisposeAsync();
            }
            return ValueTask.CompletedTask;
        }
        /// <inheritdoc/>

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            if (ExecuteTask == null)
            {
                try
                {
                    LoadLocalStaticRequest();
                    DoTimerWorkAsyn();
                    //只有云星空项目才执行
                    string sysg = LocalStaticRequest.GetSystemProfile(1, "APIGrouID");
                    if (sysg == "8")
                    {
                        LogHelper.WriteLog(string.Format("_timer.Count={0}", _timer.Count));
                        _timer.Add(new Timer(AddUnitCache, null, TimeSpan.Zero, TimeSpan.FromMinutes(20)));
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLog(string.Format("本地服务启动PushBackgroundService的ExecuteAsync方法发生错误：{0}", ex.Message));
                    StopAsync(stoppingToken);
                }
            }
            return _completedTask;
        }
    }
}
