using MainShell.Common;
using MainShell.Hardware;
using MainShell.Process;
using MainShell.ProcessResult;
using MaxwellFramework.Core.Attributes;
using System;
using System.Collections.Generic;

namespace MainShell.Motion
{
    [Singleton]
    public sealed class MotionSafetyStateProvider
    {
        private readonly IDeviceIoMonitorService _deviceIoMonitorService;
        private readonly ProcessResultManager _processResultManager;
        private readonly MachineState _machineState;

        public MotionSafetyStateProvider(IDeviceIoMonitorService deviceIoMonitorService, ProcessResultManager processResultManager, MachineState machineState = null)
        {
            _deviceIoMonitorService = deviceIoMonitorService ?? throw new ArgumentNullException(nameof(deviceIoMonitorService));
            _processResultManager = processResultManager ?? throw new ArgumentNullException(nameof(processResultManager));
            _machineState = machineState;
        }

        public MachineMode CurrentMachineMode => _machineState != null ? _machineState.CurrentMode : MachineMode.Manual;

        public bool IsEmergencyStopReleased()
        {
            if (!_deviceIoMonitorService.IsOnline)
            {
                return false;
            }

            return !_deviceIoMonitorService.IsPointOn(DeviceIoNames.WZ.EmergencyStopButton)
                && !IsSafetyCircuitHealthy();
        }

        public bool AreSafetyDoorsClosed()
        {
            if (!_deviceIoMonitorService.IsOnline)
            {
                return false;
            }

            if (_deviceIoMonitorService.IsPointOn(DeviceIoNames.WZ.SecurityDoorShield))
            {
                return true;
            }

            return _deviceIoMonitorService.IsPointOn(DeviceIoNames.WZ.SafetyDoor1Closed)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.WZ.SafetyDoor2Closed)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.WZ.SafetyDoor3Closed)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.WZ.SafetyDoor4Closed);
        }

        public bool IsFlowRunning()
        {
            var status = _processResultManager.FlowState.Status;
            return string.Equals(status, ProcessExecutionStatus.Running.ToString(), StringComparison.OrdinalIgnoreCase);
        }

        public string CurrentFlowName => _processResultManager.FlowState.WorkflowName;

        public bool AreStageVacuumsReady()
        {
            if (!_deviceIoMonitorService.IsOnline)
            {
                return false;
            }

            return _deviceIoMonitorService.IsPointOn(DeviceIoNames.Stage.Vacuum1)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.Stage.Vacuum2)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.Stage.Vacuum3)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.Stage.Vacuum4);
        }

        public IReadOnlyList<string> GetUnsafeBondHeadSignals()
        {
            if (!_deviceIoMonitorService.IsOnline)
            {
                return new[] { "DeviceIoOffline" };
            }

            var unsafeSignals = new List<string>();
            AddIfOff(unsafeSignals, DeviceIoNames.WS.BondHead1InPlace);
            AddIfOff(unsafeSignals, DeviceIoNames.WS.BondHead2InPlace);
            AddIfOff(unsafeSignals, DeviceIoNames.WS.BondHead3InPlace);
            AddIfOff(unsafeSignals, DeviceIoNames.WS.BondHead4InPlace);
            return unsafeSignals;
        }

        public bool IsAutoWorkflowSource(string source)
        {
            if (string.IsNullOrWhiteSpace(source))
            {
                return false;
            }

            return string.Equals(source, ProcessFlowName.AutoProduction, StringComparison.OrdinalIgnoreCase)
                || source.IndexOf("Auto", StringComparison.OrdinalIgnoreCase) >= 0;
        }

        private bool IsSafetyCircuitHealthy()
        {
            return _deviceIoMonitorService.IsPointOn(DeviceIoNames.General.SafetyCircuitStatus1)
                && _deviceIoMonitorService.IsPointOn(DeviceIoNames.General.SafetyCircuitStatus2);
        }

        private void AddIfOff(ICollection<string> unsafeSignals, string signalName)
        {
            if (!_deviceIoMonitorService.IsPointOn(signalName))
            {
                unsafeSignals.Add(signalName);
            }
        }
    }
}
