using PmsSecondaryPackaging.Interface.Model.Carrier;
using PmsSecondaryPackaging.Interface.Model.StepBook;
using PmsSecondaryPackaging.Interface.Model.TaskBook;
using PmsSecondaryPackaging.TaskManager.TaskBookBehavior;
using ProjectManagementSystem.Common.Config;
using ProjectManagementSystem.Common.Log;
using ProjectManagementSystem.Common.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectManagementSystem.TaskBookEvent
{
    /// <summary>
    /// PLC交互行为码，对接地址动态扩展
    /// </summary>
    public class TaskBookBehavior_PLC : BaseTaskBookBehavior
    {
        private DateTime LastStepBookExecuting { get; set; }
        public PlcBehavior PlcBehavior { get; set; }

        public TaskBookBehavior_PLC(int behavior) : base(behavior)
        {
            PlcBehavior = ExcelConfig.Instance.PlcBehaviorList.FirstOrDefault(d => d.Behavior == behavior);
        }

        public override bool TaskBookOperator(TaskDetailInfoModel taskDetailInfo, List<StepDetailInfoModel> taskStepInfoList, CarrierInfoModel carrierInfo)
        {
            try
            {
                if (Math.Abs((DateTime.Now - LastStepBookExecuting).TotalSeconds) < 1) return false;
                LastStepBookExecuting = DateTime.Now;

                var stepInfo = TaskBookRegister.GetCurrentStepDetailInfo(taskDetailInfo, taskStepInfoList);

                //写入
                if (!Interaction(0, PlcBehavior.DbAddressWrite, PlcBehavior.DbValueWrite, taskDetailInfo, stepInfo))
                {
                    return false;
                }

                //读取
                if (!Interaction(1, PlcBehavior.DbAddressRead, PlcBehavior.DbValueRead, taskDetailInfo, stepInfo))
                {
                    return false;
                }

                //最终写入
                if (!Interaction(0, PlcBehavior.DbAddressFinalWrite, PlcBehavior.DbValueFinalWrite, taskDetailInfo, stepInfo))
                {
                    return false;
                }

                TaskBookRegister.Log(taskDetailInfo, stepInfo, GetLog(taskDetailInfo, stepInfo));
                return true;
            }
            catch (Exception ex)
            {
                TaskBookRegister.LogException(ex);
            }
            return false;
        }

        private bool Interaction(int flag, string[] addrArray, bool[] valueArray, TaskDetailInfoModel taskDetailInfo, StepDetailInfoModel taskStepInfo)
        {
            if (addrArray.Length <= 0) return true;

            var routeConfig = ExcelConfig.Instance.GetRouteConfig(taskStepInfo.WareHouseID);
            if (routeConfig == null)
            {
                TaskBookRegister.Log(taskDetailInfo, taskStepInfo, "查找库位配置信息失败");
                return false;
            }
            if (string.IsNullOrEmpty(routeConfig.PlcIpAddr))
            {
                TaskBookRegister.Log(taskDetailInfo, taskStepInfo, "PlcIp地址为空");
                return false;
            }
            var plc = PlcControl.Instance.GetPlcReadWrite(routeConfig.PlcIpAddr);


            for (int i = 0; i < addrArray.Length; i++)
            {
                string addrDesc = addrArray[i];
                string plcAddr = PlcControl.Instance.GetPlcTaskAddr(taskStepInfo.WareHouseID, addrDesc);
                if (string.IsNullOrEmpty(plcAddr))
                {
                    TaskBookRegister.Log(taskDetailInfo, taskStepInfo, $"查找地址失败：“{addrDesc}”");
                    return false;
                }

                bool plcValue = GetArrayValue(valueArray, i);

                if(flag == 0)
                {
                    if (!WriteBool(plc, plcAddr, plcValue, taskDetailInfo, taskStepInfo))
                    {
                        return false;
                    }
                }
                else
                {
                    if(!ReadBool(plc, plcAddr, plcValue, taskDetailInfo, taskStepInfo))
                    {
                        return false;
                    }
                }
            }

            return true;
        }
        private bool WriteBool(HslCommunication.Core.IReadWriteNet plc, string plcAddr, bool plcValue, TaskDetailInfoModel taskDetailInfo, StepDetailInfoModel taskStepInfo)
        {
            var result = plc.Write(plcAddr, plcValue);
            if (!result.IsSuccess)
            {
                TaskBookRegister.Log(taskDetailInfo, taskStepInfo, $"写入失败({plcAddr}写入{plcValue})");
                return false;
            }

            var readResult = plc.ReadBool(plcAddr);
            if (readResult.IsSuccess)
            {
                if (readResult.Content != plcValue)
                {
                    TaskBookRegister.Log(taskDetailInfo, taskStepInfo, $"写入检查失败(读取{plcAddr}!={plcValue})");
                    return false;
                }
            }
            else
            {
                TaskBookRegister.Log(taskDetailInfo, taskStepInfo, $"写入检查失败(读取{plcAddr}失败)");
                return false;
            }

            return true;
        }

        private bool ReadBool(HslCommunication.Core.IReadWriteNet plc, string plcAddr, bool plcValue, TaskDetailInfoModel taskDetailInfo, StepDetailInfoModel taskStepInfo)
        {
            var result = plc.ReadBool(plcAddr);
            if (!result.IsSuccess
                || result.Content != plcValue)
            {
                TaskBookRegister.Log(taskDetailInfo, taskStepInfo, $"等待信号({plcAddr}={plcValue})");
                return false;
            }

            return true;
        }

        private string GetLog(TaskDetailInfoModel taskDetailInfo, StepDetailInfoModel taskStepInfo)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(PlcBehavior.Remark);

            sb.Append("【");
            for (int i = 0; i < PlcBehavior.DbAddressWrite.Length; i++)
            {
                string plcAddr = PlcControl.Instance.GetPlcTaskAddr(taskStepInfo.WareHouseID, PlcBehavior.DbAddressWrite[i]);
                bool plcValue = GetArrayValue(PlcBehavior.DbValueWrite, i);

                sb.Append($" {plcAddr}已写{plcValue};");
            }

            for (int i = 0; i < PlcBehavior.DbAddressRead.Length; i++)
            {
                string plcAddr = PlcControl.Instance.GetPlcTaskAddr(taskStepInfo.WareHouseID, PlcBehavior.DbAddressRead[i]);
                bool plcValue = GetArrayValue(PlcBehavior.DbValueRead, i);

                sb.Append($" 已等待{plcAddr}={plcValue};");
            }

            for (int i = 0; i < PlcBehavior.DbAddressFinalWrite.Length; i++)
            {
                string plcAddr = PlcControl.Instance.GetPlcTaskAddr(taskStepInfo.WareHouseID, PlcBehavior.DbAddressFinalWrite[i]);
                bool plcValue = GetArrayValue(PlcBehavior.DbValueFinalWrite, i);

                sb.Append($" {plcAddr}已最终写{plcValue};");
            }
            sb.Append("】");

            return sb.ToString();
        }

        private bool GetArrayValue(bool[] array, int index)
        {
            if (array.Length == 0) return false;
            return array.Length > index ? array[index] : array[array.Length - 1];
        }
    }
}
