using HighWayIot.Repository.domain;
using HslCommunication;
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace HighWayIot.Plc.PlcHelper
{
    public class RecipeParaHelper
    {
        /// <summary>
        /// 数据下传到PLC
        /// </summary>
        /// <param name="paraEntity"></param>
        /// <param name="positionParaEntity"></param>
        /// <returns></returns>
        public bool UploadToPLC(ZxRecipeParaEntity paraEntity, List<ZxRecipePositionParaEntity> positionParaEntity)
        {
            byte[] bytes = new byte[240];
            //SPEC编号写入
            try
            {
                if (!PlcConnect.MelsecInstance2.Write("D206", uint.Parse(paraEntity.SpecCode)).IsSuccess)
                    return false;
            }
            catch
            {
                return false;
            }

            //SPEC名称写入
            var specNameBytes = Encoding.ASCII.GetBytes(paraEntity.SpecName);
            Array.Copy(specNameBytes, 0, bytes, 0, specNameBytes.Length);
            //if (!PlcConnect.PlcWrite2("D290", paraEntity.SpecName, DataTypeEnum.String).IsSuccess)
            //    return false;

            //工位参数写入
            foreach (ZxRecipePositionParaEntity e in positionParaEntity)
            {
                bytes = SelectSetPositionPara(e, bytes);
            }

            //公共参数写入
            byte[] bitDatas = new byte[2];
            bitDatas[0] = bitDatas[0].SetBoolByIndex(1, paraEntity.S2 ?? false);
            bitDatas[0] = bitDatas[0].SetBoolByIndex(2, paraEntity.S3 ?? false);
            bitDatas[0] = bitDatas[0].SetBoolByIndex(3, paraEntity.S4 ?? false);
            bitDatas[0] = bitDatas[0].SetBoolByIndex(4, paraEntity.S5 ?? false);
            bitDatas[0] = bitDatas[0].SetBoolByIndex(5, paraEntity.S6 ?? false);
            bitDatas[0] = bitDatas[0].SetBoolByIndex(6, paraEntity.S7 ?? false);
            bitDatas[0] = bitDatas[0].SetBoolByIndex(7, paraEntity.S8 ?? false);
            bitDatas[1] = bitDatas[1].SetBoolByIndex(0, paraEntity.S9 ?? false);
            ushort bitData = bitDatas.FromBytes();

            //if (!PlcConnect.PlcWrite2("D390", bitData, DataTypeEnum.UInt16).IsSuccess)
            //    return false;

            //if (!PlcConnect.PlcWrite2("D391", paraEntity.RimInch ?? 0, DataTypeEnum.UInt16).IsSuccess)
            //    return false;
            //if (!PlcConnect.PlcWrite2("D392", paraEntity.LightWidth ?? 0, DataTypeEnum.UInt16).IsSuccess)
            //    return false;
            //if (!PlcConnect.PlcWrite2("D393", paraEntity.SlowDistance ?? 0, DataTypeEnum.UInt16).IsSuccess)
            //    return false;
            //if (!PlcConnect.PlcWrite2("D394", paraEntity.StopDistance ?? 0, DataTypeEnum.UInt16).IsSuccess)
            //    return false;
            //if (!PlcConnect.PlcWrite2("D398", paraEntity.TireWeight ?? 0, DataTypeEnum.Float).IsSuccess)
            //    return false;
            var bytes1 = BitConverter.GetBytes(bitData);
            var bytes2 = BitConverter.GetBytes((ushort?)paraEntity.RimInch ?? 0);
            var bytes3 = BitConverter.GetBytes((ushort?)paraEntity.LightWidth ?? 0);
            var bytes4 = BitConverter.GetBytes((ushort?)paraEntity.SlowDistance ?? 0);
            var bytes5 = BitConverter.GetBytes((ushort?)paraEntity.StopDistance ?? 0);
            var bytes6 = BitConverter.GetBytes(paraEntity.TireWeight ?? 0);
            Array.Copy(bytes1, 0, bytes, (390 - 290) * 2, bytes1.Length);
            Array.Copy(bytes2, 0, bytes, (391 - 290) * 2, bytes1.Length);
            Array.Copy(bytes3, 0, bytes, (392 - 290) * 2, bytes1.Length);
            Array.Copy(bytes4, 0, bytes, (393 - 290) * 2, bytes1.Length);
            Array.Copy(bytes5, 0, bytes, (394 - 290) * 2, bytes1.Length);
            Array.Copy(bytes6, 0, bytes, (398 - 290) * 2, bytes1.Length);


            return PlcConnect.MelsecInstance2.Write("D290", bytes).IsSuccess;
        }

        /// <summary>
        /// 分类工位确定点位写入
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        private byte[] SelectSetPositionPara(ZxRecipePositionParaEntity entity, byte[] bytes)
        {
            if (entity.Position == 1)
            {
                return SetPositionPara(entity, 310, bytes);
            }
            else if (entity.Position == 2)
            {
                return SetPositionPara(entity, 320, bytes);
            }
            else if (entity.Position == 3)
            {
                return SetPositionPara(entity, 330, bytes);
            }
            else if (entity.Position == 4)
            {
                return SetPositionPara(entity, 350, bytes);
            }
            else if (entity.Position == 5)
            {
                return SetPositionPara(entity, 370, bytes);
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 工位参数写入PLC
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="add"></param>
        /// <returns></returns>
        private byte[] SetPositionPara(ZxRecipePositionParaEntity entity, int add, byte[] bytes)
        {
            for (int i = 1; i <= 10; i++)
            {
                var prop = entity.GetType().GetProperty($"E{i}");
                // 检查属性是否存在
                if (prop == null)
                    return null;

                // 获取属性值
                object value = prop.GetValue(entity);

                // 处理可空类型的null值情况
                if (value == null)
                {
                    // 根据业务需求选择：返回false或使用默认值（例如0）
                    continue;
                    //if (PlcConnect.PlcWrite2($"D{add}", 0, DataTypeEnum.UInt16).IsSuccess)
                    //    return false;
                }

                // 尝试转换值  
                ushort valueToWrite;
                try
                {
                    valueToWrite = Convert.ToUInt16(value);
                }
                catch
                {
                    // 转换失败（如类型不匹配）
                    continue;
                }

                // 写入PLC并检查结果
                var resultbytes = BitConverter.GetBytes(valueToWrite);
                Array.Copy(resultbytes, 0, bytes, (add - 290) * 2, resultbytes.Length);
                //if (!PlcConnect.PlcWrite2($"D{add}", valueToWrite, DataTypeEnum.UInt16).IsSuccess)
                //    return false;

                add++;
            }
            return bytes;
        }

        /// <summary>
        /// 从PLC中读取数据
        /// </summary>
        public List<ZxRecipePositionParaEntity> DownLoadFormPlc(ref ZxRecipeParaEntity paraEntity)
        {
            //一次性读取
            OperateResult<byte[]> result = PlcConnect.MelsecInstance2.Read("D290", 120);
            byte[] data;
            if (result.IsSuccess)
            {
                data = result.Content;
            }
            else
            {
                return new List<ZxRecipePositionParaEntity>();
            }

            //读取SPEC编号
            paraEntity.SpecCode = PlcConnect.MelsecInstance2.ReadUInt32("D206").ToString();

            //读取SPEC名称
            paraEntity.SpecName = PlcConnect.MelsecInstance2.ByteTransform.TransString(data, 0, 10, Encoding.ASCII);

            //读取工位参数
            List<ZxRecipePositionParaEntity> positionEntitys = SelectReadPositionPara(data);

            //公共参数读取
            ushort bitData = PlcConnect.MelsecInstance2.ByteTransform.TransUInt16(data, (390 - 290) * 2);
            byte[] bitDatas = bitData.ToBytes();
            paraEntity.S2 = bitDatas[0].GetBoolByIndex(1);//390.1
            paraEntity.S3 = bitDatas[0].GetBoolByIndex(2);
            paraEntity.S4 = bitDatas[0].GetBoolByIndex(3);
            paraEntity.S5 = bitDatas[0].GetBoolByIndex(4);
            paraEntity.S6 = bitDatas[0].GetBoolByIndex(5);
            paraEntity.S7 = bitDatas[0].GetBoolByIndex(6);
            paraEntity.S8 = bitDatas[0].GetBoolByIndex(7);
            paraEntity.S9 = bitDatas[1].GetBoolByIndex(0);//390.8

            paraEntity.RimInch = PlcConnect.MelsecInstance2.ByteTransform.TransInt16(data, (391 - 290) * 2);//("D391");
            paraEntity.LightWidth = PlcConnect.MelsecInstance2.ByteTransform.TransInt16(data, (392 - 290) * 2);//("D392");
            paraEntity.SlowDistance = PlcConnect.MelsecInstance2.ByteTransform.TransInt16(data, (393 - 290) * 2);//("D393");
            paraEntity.StopDistance = PlcConnect.MelsecInstance2.ByteTransform.TransInt16(data, (394 - 290) * 2);//("D394");
            paraEntity.TireWeight = PlcConnect.MelsecInstance2.ByteTransform.TransSingle(data, (398 - 290) * 2);//("D398");

            return positionEntitys;
        }

        /// <summary>
        /// 分类工位循环写入
        /// </summary>
        /// <param name=""></param>
        /// <returns></returns>
        private List<ZxRecipePositionParaEntity> SelectReadPositionPara(byte[] data)
        {
            List<ZxRecipePositionParaEntity> e = new List<ZxRecipePositionParaEntity>
            {
                ReadPositionPara(310-290, data),
                ReadPositionPara(320-290, data),
                ReadPositionPara(330-290, data),
                ReadPositionPara(350-290, data),
                ReadPositionPara(370-290, data),
            };



            return e;
        }

        /// <summary>
        /// 工位参数读取PLC
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="add"></param>
        /// <returns></returns>
        private ZxRecipePositionParaEntity ReadPositionPara(int add, byte[] data)
        {
            ZxRecipePositionParaEntity entity = new ZxRecipePositionParaEntity();

            if (add == 310 - 290) entity.Position = 1;
            if (add == 320 - 290) entity.Position = 2;
            if (add == 330 - 290) entity.Position = 3;
            if (add == 350 - 290) entity.Position = 4;
            if (add == 370 - 290) entity.Position = 5;

            for (int i = 1; i <= 10; i++)
            {
                var prop = entity.GetType().GetProperty($"E{i}");
                prop.SetValue(entity, (int)PlcConnect.MelsecInstance2.ByteTransform.TransInt16(data, add * 2));
                add++;
            }

            return entity;
        }
    }
}
