using Admin.NET.Core.Service;
using DocumentFormat.OpenXml.Office2010.ExcelAc;
using Furion.InstantMessaging;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WCS.Application;

/// <summary>
/// 任务日志集线器
/// </summary>
[MapHub("/hubs/PlcDevice")]
public class PlcDeviceHub : Hub<IPlcDeviceHub>
{
    private static readonly SysCacheService _sysCacheService = App.GetRequiredService<SysCacheService>();
    private static bool boRunningState = false;
    private static CancellationTokenSource cts;//取消线程标识
    private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
    public PlcDeviceHub()
    {
    }

    /// <summary>
    /// 连接
    /// </summary>
    /// <returns></returns>
    public override async Task OnConnectedAsync()
    {
        var httpContext = Context.GetHttpContext();
        var userId = (httpContext.User.FindFirst(ClaimConst.UserId)?.Value).ToLong();
        _sysCacheService.Set("PlcDeviceHub:" + Context.ConnectionId, userId);
        if (!boRunningState)
        {
            //开启读取服务线程
            boRunningState = true;
            cts = new CancellationTokenSource();//取消线程标识
            StartRead();
        }
        await base.OnConnectedAsync();
    }

    /// <summary>
    /// æ–­å¼€
    /// </summary>
    /// <param name="exception"></param>
    /// <returns></returns>
    public override async Task OnDisconnectedAsync(Exception exception)
    {
        _sysCacheService.Remove("PlcDeviceHub:" + Context.ConnectionId);
        //如果没有连接了 就关闭线程不读了
        if (_sysCacheService.GetKeysByPrefixKey("PlcDeviceHub").Count == 0)
        {
            cts.Cancel();
            boRunningState = false;
        }
        await base.OnDisconnectedAsync(exception);
    }

    /// <summary>
    /// 开启读取plc线程
    /// </summary>
    public static void StartRead()
    {
        Task.Run(() =>
        {
            // 用于保存每个设备的初始状态
            var initialStates = new Dictionary<long, WcsDeviceOutput>();

            var listPlc = _db.Queryable<WcsPlc>().Where(s => s.Type == PLCTypeEnum.StackingMachine || s.Type == PLCTypeEnum.ConveyorLine).Where(s => s.Enable == YesNoEnum.Y).ToList();
            var listPlcId = listPlc.Select(s => s.Id).ToList();
            var listPlcDevice = _db.Queryable<WcsDevice>().Where(s => s.DeviceType == DeviceTypeEnum.Business && listPlcId.Contains(s.PlcId) && s.IsDelete).Select<WcsDeviceOutput>().ToList();
            var listPlcDeviceId = listPlcDevice.Select(s => s.Id).ToList();
            var listPlcStation = _db.Queryable<WcsPosition>().Where(s => listPlcDeviceId.Contains(s.DeviceId)).ToList();
            while (true)
            {
                try
                {
                    //获取跺机的状态
                    foreach (var modDevice in listPlcDevice)
                    {
                        //取消线程
                        if (cts.Token.IsCancellationRequested)
                        {
                            throw new OperationCanceledException();
                        }
                        var modPlc = listPlc.Where(s => s.Id == modDevice.PlcId).FirstOrDefault();
                        modDevice.Type = modPlc.Type;
                        //读取plc的值
                        var modConn = PLCTaskAction.listPlcConn.FirstOrDefault(s => s != null && s.PlcId == modDevice.PlcId);
                        if (modConn == null)
                        {
                            modDevice.Status = false;
                            continue;
                        }
                        else
                        {
                            modDevice.Status = modConn.Connected;
                        }
                        if (modConn.Connected)
                        {
                            var listPosition = listPlcStation.Where(s => s.DeviceId == modDevice.Id).ToList();
                            (var result, var plc) = modConn.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos);
                            modDevice.Plc = Convert.ToString(plc);
                            (result, var wcs) = modConn.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos);
                            modDevice.Wcs = Convert.ToString(wcs);
                            //任务号
                            var modPositionTask = listPosition.FirstOrDefault(s => s.Text == "任务号");
                            if (modPositionTask != null)
                            {
                                (result, var taskNo) = modConn.GetPlcDBValue(modPositionTask.PosType, modDevice.DbNumber, modPositionTask.PlcPos, modPositionTask.StringLength);
                                modDevice.TaskNo = Convert.ToString(taskNo);
                            }
                            //任务类型
                            var modPositionTaskType = listPosition.FirstOrDefault(s => s.Text == "任务类型");
                            if (modPositionTaskType != null)
                            {
                                (result, var taskType) = modConn.GetPlcDBValue(modPositionTaskType.PosType, modDevice.DbNumber, modPositionTaskType.PlcPos);
                                modDevice.TaskType = (TaskTypeEnum)Convert.ToInt32(taskType);
                            }
                            //起始工位
                            var modPositionStartLocatNo = listPosition.FirstOrDefault(s => s.Text == "起始工位");
                            if (modPositionStartLocatNo != null)
                            {
                                (result, var startLocatNo) = modConn.GetPlcDBValue(modPositionStartLocatNo.PosType, modDevice.DbNumber, modPositionStartLocatNo.PlcPos);
                                modDevice.StartLocatNo = Convert.ToString(startLocatNo);
                            }
                            //目的工位
                            var modPositionEndLocatNo = listPosition.FirstOrDefault(s => s.Text == "目的工位");
                            if (modPositionEndLocatNo != null)
                            {
                                (result, var endLocatNo) = modConn.GetPlcDBValue(modPositionEndLocatNo.PosType, modDevice.DbNumber, modPositionEndLocatNo.PlcPos);
                                modDevice.EndLocatNo = Convert.ToString(endLocatNo);
                            }
                            //托盘码
                            var modPositionPalletNo = listPosition.FirstOrDefault(s => s.Text == "托盘码");
                            if (modPositionPalletNo != null)
                            {
                                (result, var palletNo) = modConn.GetPlcDBValue(modPositionPalletNo.PosType, modDevice.DbNumber, modPositionPalletNo.PlcPos, modPositionPalletNo.StringLength);
                                modDevice.PalletNo = Convert.ToString(palletNo);
                            }
                            if (modPlc.Type == PLCTypeEnum.ConveyorLine)
                            {
                                //放货排
                                var modPositionReleaseRow = listPosition.FirstOrDefault(s => s.Text == "放货排");
                                if (modPositionReleaseRow != null)
                                {
                                    (result, var releaseRow) = modConn.GetPlcDBValue(modPositionReleaseRow.PosType, modDevice.DbNumber, modPositionReleaseRow.PlcPos);
                                    modDevice.ReleaseRow = Convert.ToInt32(releaseRow);
                                }
                                //放货列
                                var modPositionReleaseCol = listPosition.FirstOrDefault(s => s.Text == "放货列");
                                if (modPositionReleaseCol != null)
                                {
                                    (result, var releaseCol) = modConn.GetPlcDBValue(modPositionReleaseCol.PosType, modDevice.DbNumber, modPositionReleaseCol.PlcPos);
                                    modDevice.ReleaseCol = Convert.ToInt32(releaseCol);
                                }
                                //放货层
                                var modPositionReleaseStorey = listPosition.FirstOrDefault(s => s.Text == "放货层");
                                if (modPositionReleaseStorey != null)
                                {
                                    (result, var releaseStorey) = modConn.GetPlcDBValue(modPositionReleaseStorey.PosType, modDevice.DbNumber, modPositionReleaseStorey.PlcPos);
                                    modDevice.ReleaseStorey = Convert.ToInt32(releaseStorey);
                                }
                                //取货排
                                var modPositionPickRow = listPosition.FirstOrDefault(s => s.Text == "取货排");
                                if (modPositionPickRow != null)
                                {
                                    (result, var pickRow) = modConn.GetPlcDBValue(modPositionPickRow.PosType, modDevice.DbNumber, modPositionPickRow.PlcPos);
                                    modDevice.PickRow = Convert.ToInt32(pickRow);
                                }
                                //取货列
                                var modPositionPickCol = listPosition.FirstOrDefault(s => s.Text == "取货列");
                                if (modPositionPickCol != null)
                                {
                                    (result, var pickCol) = modConn.GetPlcDBValue(modPositionPickCol.PosType, modDevice.DbNumber, modPositionPickCol.PlcPos);
                                    modDevice.PickCol = Convert.ToInt32(pickCol);
                                }
                                //取货层
                                var modPositionPickStorey = listPosition.FirstOrDefault(s => s.Text == "取货层");
                                if (modPositionPickStorey != null)
                                {
                                    (result, var pickStorey) = modConn.GetPlcDBValue(modPositionPickStorey.PosType, modDevice.DbNumber, modPositionPickStorey.PlcPos);
                                    modDevice.PickStorey = Convert.ToInt32(pickStorey);
                                }

                                if (modPlc.Type == PLCTypeEnum.StackingMachine)
                                {
                                    //跺机的起始工位用取货排列层
                                    modDevice.StartLocatNo = $"{modDevice.PickRow.ToString()}{modDevice.PickCol.ToString()}{modDevice.PickStorey.ToString()}";
                                    //跺机的目的工位用放货排列层
                                    modDevice.EndLocatNo = $"{modDevice.ReleaseRow.ToString()}{modDevice.ReleaseCol.ToString()}{modDevice.ReleaseStorey.ToString()}";
                                }
                            }
                        }
                        //else
                        //{
                        //    //测试
                        //    modDevice.TaskNo = "TK00001";
                        //    modDevice.TaskType = TaskTypeEnum.In;
                        //    modDevice.Wcs = new Random().Next(1000).ToString();
                        //    modDevice.Plc = new Random().Next(1000).ToString();
                        //    modDevice.Status = true;
                        //}
                        // 比较之前的状态
                        if (initialStates.TryGetValue(modDevice.Id, out var initialState))
                        {
                            if (modDevice.Status != initialState.Status ||
                                (modDevice.Plc.IsNullOrEmpty() && modDevice.Plc != initialState.Plc) ||
                                modDevice.Wcs != initialState.Wcs ||
                                modDevice.TaskNo != initialState.TaskNo ||
                                modDevice.TaskType != initialState.TaskType ||
                                modDevice.StartLocatNo != initialState.StartLocatNo ||
                                modDevice.EndLocatNo != initialState.EndLocatNo ||
                                modDevice.PalletNo != initialState.PalletNo ||
                                (modPlc.Type == PLCTypeEnum.ConveyorLine &&
                                    (modDevice.ReleaseRow != initialState.ReleaseRow ||
                                     modDevice.ReleaseCol != initialState.ReleaseCol ||
                                     modDevice.ReleaseStorey != initialState.ReleaseStorey ||
                                     modDevice.PickRow != initialState.PickRow ||
                                     modDevice.PickCol != initialState.PickCol ||
                                     modDevice.PickStorey != initialState.PickStorey)))
                            {
                                // 通知用户变更
                                HubUtil.PublicPlcDevice(modDevice);
                            }
                        }
                        initialStates[modDevice.Id] = modDevice.Adapt<WcsDeviceOutput>();
                    }
                    Thread.Sleep(2000);
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception)
                {

                }
            }
        }, cts.Token);
    }
}