using Admin.Core.IService;
using Admin.Core.Model;
using Admin.Core.Service;
using Aucma.Scada.UI.Common;
using log4net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Aucma.Scada.UI
{
    /// <summary>
    /// 入库业务逻辑
    /// </summary>
    public  class InStoreBusiness
    {
        #region 单例实现
        //private static readonly InStoreBusiness lazy = new InStoreBusiness();
        //public static InStoreBusiness Instance
        //{
        //    get
        //    {
        //        return lazy;
        //    }
        //}
        #endregion

        #region 对象引用
        private static readonly log4net.ILog logHelper = LogManager.GetLogger(typeof(ExecutePlanInfoServices));

        private AppConfig appConfig = new  AppConfig();//AppConfig.Instance;
        //??????????????????????????????
        //private InStoreTaskHandle taskHandle = InStoreTaskHandle.Instance;

        //private GrabImage grabImage = GrabImage.Instance;

        #endregion

        #region 接口引用
        /// <summary>
        /// 货道信息
        /// </summary>
        private IBaseSpaceInfoServices _spaceInfoService;

        /// <summary>
        /// 实时任务
        /// </summary>
        private IRealTaskInfoServices _taskInfoService;

        private IBaseSpaceDetailServices _baseSpaceDetailService;

        private IBaseBomInfoServices _baseBomInfoService;

        private IRecordInStoreServices _recordInStore;
        #endregion

        #region 委托事件
        /// <summary>
        /// 初始化入库任务
        /// </summary>
        /// <param name="message"></param>
        public delegate void RefreshInStoreTask(RealTaskInfo taskInfos, bool isFinsih = false);
        public event RefreshInStoreTask RefreshInStoreTaskEvent;

        /// <summary>
        /// 扫码信息刷新
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="materialName"></param>
        /// <param name="spaceName"></param>
        /// <param name="materialType"></param>
        public delegate void RefreshScanMateriaCode(string materialCode, string materialName, string spaceName, string materialType);
        public event RefreshScanMateriaCode RefreshScanMateriaCodeEvent;

        /// <summary>
        /// 日志信息刷新
        /// </summary>
        /// <param name="message"></param>
        public delegate void RefreshLogMessage(string message);
        public event RefreshLogMessage RefreshLogMessageEvent;

        #endregion

        public InStoreBusiness()
        {
            _spaceInfoService = App.ServiceProvider.GetService<IBaseSpaceInfoServices>();
            _taskInfoService = App.ServiceProvider.GetService<IRealTaskInfoServices>();
            _baseSpaceDetailService = App.ServiceProvider.GetService<IBaseSpaceDetailServices>();
            _baseBomInfoService = App.ServiceProvider.GetService<IBaseBomInfoServices>();
            _recordInStore = App.ServiceProvider.GetService<IRecordInStoreServices>();

            //taskHandle.InStoreFinsihEvent += InStoreFinish;
            //taskHandle.InStoreAnswerEvent += InStoreAnswer;

            //grabImage.RefreshMaterialCodeStrEvent += InStore;
            //grabImage.RefreshLogMessageEvent += PrintLogInfoMessage;

            StartPassDown();

            //Task.Run(() =>
            //{
            //    Thread.Sleep(6000);
            //    for (int i = 1; i < 12; i++)
            //    {
            //        InStore(appConfig.shellStoreCode, "B23600000781110900" + i.ToString().PadLeft(2, '0'));
            //        Thread.Sleep(1000 * 30);
            //        InStore(appConfig.linerStoreCode, "L23600000788110900" + i.ToString().PadLeft(2, '0'));
            //        Thread.Sleep(1000 * 30);
            //    }
            //});

        }

        /// <summary>
        /// 入库
        /// </summary>
        /// <param name="storeCode"></param>
        /// <param name="materialType"></param>
        private async void InStore(string storeCode, string materialCode)
        {
            try
            {
                PrintLogInfoMessage($"扫码成功,物料码:{materialCode}");
                string materialType = SubStringMaterialCode(materialCode);
                #region Delete By wenjy 2023-10-30 11:41:00 取消通过数据库获取货道数量、在途量,改为通过PLC获取货道信息
                //var spaceInfo = _spaceInfoService.InStoreGetSpaceInfoByMaterialType(storeCode, materialType);
                #endregion
                var spaceInfo =await GetSpaceInfoByMaterialType(storeCode, materialType);
                if (spaceInfo != null)
                {
                    PrintLogInfoMessage($"匹配货道:{spaceInfo.SpaceName}");
                    spaceInfo.MaterialType = materialType;
                    RefreshScanMateriaCodeEvent?.Invoke(materialCode,await GetMaterialName(materialType), spaceInfo.SpaceName, storeCode); //刷新界面扫码信息
                    var result =await CreateInStoreTask(spaceInfo, materialCode); //创建入库任务
                    if (result)
                    {
                        //spaceInfo.onRouteAmount += 1; //通过PLC获取货道信息(在库、在途数量)时不需要修改在途数量
                        _spaceInfoService.UpdateSpaceInfo(spaceInfo);
                    }
                }
                else
                {
                    //报警停线
                    PrintLogInfoMessage($"物料码:{materialCode};未匹配到可用货道");
                }
            }
            catch (Exception ex)
            {
                PrintLogErrorMessage("入库业务异常", ex);
            }
        }

        /// <summary>
        /// 创建入库任务
        /// </summary>
        /// <param name="spaceInfo"></param>
        private async Task<bool> CreateInStoreTask(BaseSpaceInfo spaceInfo, string materialCode)
        {
            bool result = false;

            #region 任务赋值
            RealTaskInfo realTaskInfo = new RealTaskInfo();
            realTaskInfo.TaskType = 1;
            realTaskInfo.TaskCode = System.Guid.NewGuid().ToString("N").Substring(0, 6);
            realTaskInfo.StoreCode = spaceInfo.StoreCode;
            realTaskInfo.SpaceCode = spaceInfo.SpaceCode;
            realTaskInfo.MaterialType = spaceInfo.MaterialType;
            realTaskInfo.MaterialCode = materialCode;
            realTaskInfo.PlanAmount = 1;
            realTaskInfo.TaskStatus = 1;
            realTaskInfo.CreateTime = DateTime.Now;
            #endregion

            int r =await _taskInfoService.AddAsync(realTaskInfo);
            if (r>0)
            {
                PrintLogInfoMessage("入库任务创建成功");

                RefreshInStoreTaskEvent?.Invoke(realTaskInfo);

                result = true;
            }
            else
            {
                PrintLogInfoMessage("入库任务创建失败");
            }
            return result;
        }

        #region 轮询获取入库任务下发至PLC,等待PLC执行反馈,完成后再次下发

        private SemaphoreSlim shellSemaphore = new SemaphoreSlim(0);

        private SemaphoreSlim linerSemaphore = new SemaphoreSlim(0);

        /// <summary>
        /// 任务下发  ——迁移到任务调度中去
        /// </summary>
        [Obsolete("迁移到任务调度中去,废弃")]
        private void StartPassDown()
        {

            Thread.Sleep(5000);
            Task.Run(() =>
            {
                while (true)
                {
                    PassDownShellTask();
                    Thread.Sleep(5000);
                }
            });

            Task.Run(async () =>
            {
                while (true)
                {
                   await  PassDownLinerTaskAsync();
                    Thread.Sleep(5000);
                }
            });
        }


        /// <summary>
        /// 依次获取箱壳任务队列进行下发
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private async void PassDownShellTask()
        {
            try
            {
                RealTaskInfo taskInfo =await _taskInfoService.GetTaskInfoByStoreCode(appConfig.shellStoreCode, appConfig.instoreTaskType);
                if (taskInfo != null)
                {
                    PrintLogInfoMessage($"下发箱壳入库任务:{taskInfo.TaskCode};仓库{taskInfo.StoreCode};货道:{taskInfo.SpaceCode}");

                    //if (taskHandle.SendShellTask_InStore(taskInfo))
                    {
                        PrintLogInfoMessage($"箱壳入库任务:{taskInfo.TaskCode};下发成功,等待PLC执行反馈");

                        shellSemaphore.Wait(); //一直堵塞直到信号量释放

                        PrintLogInfoMessage($"箱壳入库任务:{taskInfo.TaskCode};开始执行");

                        taskInfo.TaskStatus = 2;

                        _taskInfoService.UpdateAsync(taskInfo);

                        RefreshInStoreTaskEvent?.Invoke(taskInfo);
                    }
                    //else
                    //{
                    //    PrintLogInfoMessage($"箱壳入库任务:{taskInfo.TaskCode};下发失败,请排查PLC连接");
                    //}

                }
                else
                {
                    PrintLogInfoMessage("未获取到需要下发的箱壳入库任务");
                }
            }
            catch (Exception ex)
            {
                PrintLogErrorMessage("依次获取箱壳任务队列进行下发逻辑异常", ex);
            }
        }

        /// <summary>
        /// 依次获取内胆任务队列进行下发
        /// </summary>
        private async Task PassDownLinerTaskAsync()
        {
            try
            {
                RealTaskInfo taskInfo = await _taskInfoService.GetTaskInfoByStoreCode(appConfig.linerStoreCode, appConfig.instoreTaskType);
                if (taskInfo != null)
                {
                    PrintLogInfoMessage($"下发内胆入库任务:{taskInfo.TaskCode};仓库{taskInfo.StoreCode};货道:{taskInfo.SpaceCode}");

                    //if (taskHandle.SendLinerTask_InStore(taskInfo))
                    {
                        PrintLogInfoMessage($"内胆入库任务:{taskInfo.TaskCode};下发成功,等待PLC执行反馈");

                        linerSemaphore.Wait(); //一直堵塞直到信号量释放

                        PrintLogInfoMessage($"内胆入库任务:{taskInfo.TaskCode};开始执行");

                        taskInfo.TaskStatus = 2;

                        _taskInfoService.UpdateAsync(taskInfo);

                        RefreshInStoreTaskEvent?.Invoke(taskInfo);
                    }
                    //else
                    //{
                    //    PrintLogInfoMessage($"内胆入库任务:{taskInfo.TaskCode};下发失败,请排除PLC连接");
                    //}
                }
                else
                {
                    PrintLogInfoMessage("未获取到需要下发的内胆入库任务");
                }
            }
            catch (Exception ex)
            {
                PrintLogErrorMessage("依次获取内胆任务队列进行下发逻辑异常", ex);
            }
        }
        #endregion

        /// <summary>
        /// 入库应答,PLC收到入库任务后进行应答
        /// </summary>
        /// <param name="storeCode"></param>
        /// <param name="taskCode"></param>
        private void InStoreAnswer(string storeCode, string taskCode)
        {
            if (storeCode == appConfig.shellStoreCode)
            {
                PrintLogInfoMessage("箱壳应答成功,自动释放信号量,进行下发新任务");

                shellSemaphore.Release();
            }
            else
            {
                PrintLogInfoMessage("内胆应答成功,自动释放信号量,进行下发新任务");

                linerSemaphore.Release();
            }
        }

        /// <summary>
        /// 入库完成
        /// </summary>
        /// <param name="storeCode"></param>
        /// <param name="taskCode"></param>
        private void InStoreFinish(string storeCode, string taskCode)
        {
            if (storeCode == appConfig.shellStoreCode)
            {
                PrintLogInfoMessage($"箱壳任务:{taskCode};执行完成");

                InStoreFinishHandle(taskCode, appConfig.shellStoreCode);
            }
            else
            {
                PrintLogInfoMessage($"内胆任务:{taskCode};执行完成");

                InStoreFinishHandle(taskCode, appConfig.linerStoreCode);
            }
        }

        /// <summary>
        /// 入库完成逻辑处理
        /// </summary>
        /// <param name="storeCode"></param>
        /// <param name="spaceCode"></param>
        /// <param name="materialType"></param>
        private async void InStoreFinishHandle(string taskCode, string storeCode)
        {
            try
            {
                var taskInfo =await _taskInfoService.GetTaskInfoByTaskCode(taskCode, storeCode);
                if (taskInfo != null)
                {

                    var spaceInfo =await _spaceInfoService.GetSpaceInfoBySpaceCode(taskInfo.StoreCode, taskInfo.SpaceCode);

                    if (spaceInfo != null)
                    {
                        //taskHandle.WritePlc(spaceInfo.StoreCode, spaceInfo.SpaceCode, true);
                        //spaceInfo.materialType = taskInfo.materialType;

                        spaceInfo.SpaceStock = spaceInfo.SpaceStock + 1;
                        spaceInfo.OnRouteAmount -= 1;

                        //读取PLC获取货道信息:存放数量、在途数量,
                        #region Add By wenjy 2023-10-30 13:44:00 通过PLC获取货道信息
                        //var item = taskHandle.ReadSpaceInfoByPlc(spaceInfo);
                        //spaceInfo.SpaceStock = item.spaceStock;
                        //spaceInfo.OnRouteAmount = item.onRouteAmount;
                        //spaceInfo.SpaceStatus = item.spaceStatus;
                        #endregion

                        _spaceInfoService.UpdateSpaceInfo(spaceInfo);

                        #region 添加货道明细
                        BaseSpaceDetail spaceDetail = new BaseSpaceDetail();
                        spaceDetail.MaterialType = taskInfo.MaterialType;
                        spaceDetail.MaterialCode = taskInfo.MaterialCode;
                        spaceDetail.MaterialName = await GetMaterialName(taskInfo.MaterialType);
                        spaceDetail.StoreCode = spaceInfo.StoreCode;
                        spaceDetail.SpaceCode = spaceInfo.SpaceCode;
                        spaceDetail.MaterialAmount = 1;
                       await  _baseSpaceDetailService.InsertSpaceDetail(spaceDetail);
                        #endregion

                        #region 添加入库记录
                        RecordInStore recordInstore = new RecordInStore();
                        recordInstore.StoreCode = taskInfo.StoreCode;
                        recordInstore.SpaceCode = taskInfo.SpaceCode;
                        recordInstore.MaterialCode = taskInfo.MaterialCode;
                        recordInstore.MaterialType = taskInfo.MaterialType;
                        recordInstore.MaterialName = await GetMaterialName(taskInfo.MaterialType);
                        recordInstore.InStoreAmount = 1;
                        recordInstore.InStoreTime = DateTime.Now;
                        recordInstore.BarCodeCode = taskInfo.MaterialCode;
                        await _recordInStore.AddAsync(recordInstore);
                        #endregion

                    }
                    //清除任务信息
                    _taskInfoService.DeleteTaskInfo(taskCode, storeCode);
                }
                RefreshInStoreTaskEvent?.Invoke(taskInfo, true);
            }
            catch (Exception ex)
            {
                PrintLogErrorMessage("入库完成逻辑处理异常", ex);
            }
        }

        /// <summary>
        /// 截取条码
        /// </summary>
        /// <param name="materialCode"></param>
        /// <returns></returns>
        private string SubStringMaterialCode(string materialCode)
        {
            string result = string.Empty;
            if (!string.IsNullOrEmpty(materialCode))
            {
                result = materialCode.Substring(2, 10);
            }

            return result;
        }

        /// <summary>
        /// 获取已创建的所有入库任务
        /// </summary>
        /// <returns></returns>
        public async Task<List<RealTaskInfo>> GetInStoreTask()
        {
            return await _taskInfoService.GetTaskInfosByStoreCode(new string[] { appConfig.shellStoreCode, appConfig.linerStoreCode }, appConfig.instoreTaskType);
        }

        /// <summary>
        /// 通过BOM获取物料名称
        /// </summary>
        /// <param name="materialType"></param>
        /// <returns></returns>
        public async Task<string> GetMaterialName(string materialType)
        {
            string materialName = string.Empty;
            var info =await _baseBomInfoService.GetBomInfoByMaterialCode(materialType);
            if (info != null)
            {
                materialName = info.MaterialName;
            }

            return materialName;
        }

        /// <summary>
        /// 获取仓库物料库存
        /// </summary>
        /// <returns></returns>
        public async Task<List<dynamic>> GetMaterialStock()
        {
            return await _spaceInfoService.GetMaterialStock(appConfig.shellStoreCode, appConfig.linerStoreCode);
        }

        #region 通过PLC读取货道信息:在库、在途、货道状态
        /// <summary>
        /// 通过PLC读取货道信息(在途数量、在库数量、货道状态)
        /// </summary>
        /// <param name="storeCode"></param>
        /// <param name="materialType"></param>
        /// <returns></returns>
        private async Task<BaseSpaceInfo> GetSpaceInfoByMaterialType(string storeCode, string materialType)
        {
            BaseSpaceInfo result = null;

            try
            {
                List<BaseSpaceInfo> info = await _spaceInfoService.GetBaseSpaceInfosByMaterialType(storeCode, materialType);

                if (info != null)
                {
                    if (info.Count > 0)
                    {
                        result = GetSpaceInfosByPlc(info);

                        if (result == null)
                        {
                            var list =await _spaceInfoService.GetEmptySpaceInfo(storeCode);

                            result = GetSpaceInfosByPlc(list);
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                PrintLogErrorMessage("货道信息读取异常", ex);
            }

            return result;
        }

        /// <summary>
        /// 读取PLC货道信息
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        private BaseSpaceInfo GetSpaceInfosByPlc(List<BaseSpaceInfo> info)
        {
            BaseSpaceInfo result = null;
            if (info != null)
            {
                if (info.Count > 0)
                {
                    //foreach (BaseSpaceInfo item in info)
                    //{
                    //    var spaceInfo = taskHandle.ReadSpaceInfoByPlc(item);

                    //    item.SpaceStock = spaceInfo.spaceStock;
                    //    item.OnRouteAmount = spaceInfo.onRouteAmount;
                    //    item.SpaceStatus = spaceInfo.spaceStatus;

                    //    PrintLogInfoMessage($"通过PLC读取货道信息,货道:{spaceInfo.spaceName};在库数量:{item.SpaceStock};在途数量:{item.OnRouteAmount};货道状态:{item.SpaceStatus}");
                    //}

                    var list = info.Where(x => x.SpaceStock > 0 ? x.SpaceCapacity > (x.SpaceStock + x.OnRouteAmount) : 1 == 1 && x.SpaceStatus == 1).ToList();

                    if (list.Count > 0)
                    {
                        result = list.OrderByDescending(x => x.SpaceStock).OrderBy(x => x.SpaceCode).First();
                    }

                }
            }
            return result;
        }
        #endregion

        #region 日志输出
        /// <summary>
        /// 日志输出,界面刷新同时记录文件
        /// </summary>
        /// <param name="message"></param>
        private void PrintLogInfoMessage(string message)
        {
            RefreshLogMessageEvent?.Invoke(message);
            logHelper.Info(message);
        }

        /// <summary>
        /// 异常日志输出
        /// </summary>
        /// <param name="message"></param>
        /// <param name="ex"></param>
        private void PrintLogErrorMessage(string message, Exception ex = null)
        {
            RefreshLogMessageEvent?.Invoke(message);
            logHelper.Error(message, ex);
        }
        #endregion
    }
}