using MainShell.EventArgsFolder;
using MainShell.Hardware;
using MainShell.Manual.Model;
using MainShell.Manual.ViewModel.State;
using MainShell.Resources.CustomControl;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;

namespace MainShell.Manual.ViewModel
{
    public class LogisticsOperationViewModel : OperateViewModelBase
    {
        private readonly IDeviceIoMonitorService _ioMonitorService;
        private readonly Dictionary<string, Action<bool>> _ioNameBindings = new Dictionary<string, Action<bool>>(StringComparer.OrdinalIgnoreCase);
        private readonly Dictionary<int, Action<bool>> _ioIdBindings = new Dictionary<int, Action<bool>>();

        private LogisticsOperationState _state;

        public new LogisticsOperationState State
        {
            get { return _state; }
            set { SetAndNotify(ref _state, value); }
        }

        public LogisticsOperationViewModel(IDeviceIoMonitorService ioMonitorService)
        {
            _ioMonitorService = ioMonitorService;

            State = BuildDefaultState();
            State.PropertyChanged += OnStatePropertyChanged;

            InitializeIoBindings();

            _ioMonitorService.IoChanged += OnIoSnapshotChanged;
            _ioMonitorService.Start();

            ApplyEfemMode(State.IsManualWithoutEfem);
            RequestIoRefresh();
        }

        private LogisticsOperationState BuildDefaultState()
        {
            var state = new LogisticsOperationState
            {
                SubstrateLoad = BuildSectionState("SUBSTRATE LOAD / 基板上料", "READY", "开始上料流程", "停止流程"),
                ChipLoad = BuildSectionState("CHIP LOAD / 芯片上料", "READY", "发送取料指令", "取消流程"),
                SubstrateOut = BuildSectionState("SUBSTRATE OUT / 基板下料", "IDLE", "开始下料出片", "停止流程"),
                ChipUnload = BuildSectionState("CHIP UNLOAD / 芯片下料", "AWAITING", "执行内部下料", "取消流程"),
                MagazineMap = MagazineMapViewModel.CreateDefault(25),
                FeedbackTitle = "FEEDBACK"
            };

            state.ChipLoad.PhaseSteps.Add(new PhaseStepState
            {
                Title = "Phase 1: EFEM 取料",
                Status = "READY",
                ActionText = "发送取料指令",
                IsEnabled = true,
                ControlTag = "EFEM HANDOFF",
                RequiresEfemCommunication = true,
                TargetLayer = 1
            });
            state.ChipLoad.PhaseSteps.Add(new PhaseStepState
            {
                Title = "Phase 2: 设备内部吸取",
                Status = "内部手动",
                ActionText = "执行内部动作",
                IsEnabled = false,
                ControlTag = "INTERNAL",
                RequiresEfemCommunication = false
            });

            state.ChipUnload.PhaseSteps.Add(new PhaseStepState
            {
                Title = "Phase 1: 内部移出至对接位",
                Status = "内部手动",
                ActionText = "执行内部下料",
                IsEnabled = true,
                ControlTag = "INTERNAL",
                RequiresEfemCommunication = false
            });
            state.ChipUnload.PhaseSteps.Add(new PhaseStepState
            {
                Title = "Phase 2: EFEM 返料到料盒",
                Status = "AWAITING",
                ActionText = "发送取料指令",
                IsEnabled = false,
                ControlTag = "EFEM HANDOFF",
                RequiresEfemCommunication = true,
                TargetLayer = 1
            });

            return state;
        }

        private SectionState BuildSectionState(string title, string status, string primaryAction, string secondaryAction)
        {
            return new SectionState
            {
                Title = title,
                Status = status,
                PrimaryActionText = primaryAction,
                SecondaryActionText = secondaryAction,
                Indicators =
                {
                    new IndicatorState { Name = "进片感应器触发", IsOn = false },
                    new IndicatorState { Name = "轨道电机运行中", IsOn = false },
                    new IndicatorState { Name = "平移机原点检测", IsOn = false },
                    new IndicatorState { Name = "真空吸附确认", IsOn = false }
                }
            };
        }

        public async Task ScanAsync()
        {
            if (State.IsScanning)
            {
                return;
            }

            State.IsScanning = true;
            State.ScanProgress = 0;
            State.AddFeedback("自动扫码开始。", "INFO");
            RequestIoRefresh();

            for (var i = 1; i <= 100; i++)
            {
                State.ScanProgress = i;
                await Task.Delay(20);
            }

            State.IsScanning = false;
            State.AddFeedback("自动扫码完成，共扫描 25 个槽位。", "INFO");
            RequestIoRefresh();
        }

        private void OnStatePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(LogisticsOperationState.IsManualWithoutEfem))
            {
                ApplyEfemMode(State.IsManualWithoutEfem);
            }

            RequestIoRefresh();
        }

        private void ApplyEfemMode(bool manualWithoutEfem)
        {
            if (State.ChipLoad.PhaseSteps.Count > 1)
            {
                State.ChipLoad.PhaseSteps[0].IsEnabled = !manualWithoutEfem;
                State.ChipLoad.PhaseSteps[1].IsEnabled = manualWithoutEfem;
            }

            if (State.ChipUnload.PhaseSteps.Count > 1)
            {
                State.ChipUnload.PhaseSteps[1].IsEnabled = !manualWithoutEfem;
            }

            RequestIoRefresh();
        }

        public Task ChipLoadPhase1Async()
        {
            if (State.IsManualWithoutEfem)
            {
                State.AddFeedback("CHIP LOAD: 无EFEM调试模式，直接执行设备内部芯片上料流程。", "INFO");
                return ChipLoadPhase2Async();
            }

            var layer = State.ChipLoad.PhaseSteps[0].TargetLayer;
            State.AddFeedback(string.Format("CHIP LOAD Phase1: 发送EFEM取料指令，目标料盒层 L{0:D2}（预留通讯接口）。", layer), "INFO");
            if (State.ChipLoad.PhaseSteps.Count > 1)
            {
                State.ChipLoad.PhaseSteps[1].IsEnabled = true;
            }

            RequestIoRefresh();
            return Task.CompletedTask;
        }

        public Task ChipLoadPhase2Async()
        {
            State.AddFeedback("CHIP LOAD Phase2: 执行设备内部吸取动作。", "INFO");
            RequestIoRefresh();
            return Task.CompletedTask;
        }

        public Task ChipUnloadPhase1Async()
        {
            State.AddFeedback("CHIP UNLOAD Phase1: 内部移出至对接位。", "INFO");
            RequestIoRefresh();
            return Task.CompletedTask;
        }

        public Task ChipUnloadPhase2Async()
        {
            var layer = State.ChipUnload.PhaseSteps[1].TargetLayer;
            State.AddFeedback(string.Format("CHIP UNLOAD Phase2: 发送EFEM返料指令，目标料盒层 L{0:D2}（预留通讯接口）。", layer), "INFO");
            RequestIoRefresh();
            return Task.CompletedTask;
        }

        protected override void OnDeactivate()
        {
            _ioMonitorService.IoChanged -= OnIoSnapshotChanged;
            base.OnDeactivate();
        }

        private void InitializeIoBindings()
        {
            BindIoName("LG.SubstrateLoad.SensorIn", value => SetIndicator(State.SubstrateLoad, 0, value));
            BindIoName("LG.SubstrateLoad.TrackMotorRun", value => SetIndicator(State.SubstrateLoad, 1, value));
            BindIoName("LG.SubstrateLoad.HomeChecked", value => SetIndicator(State.SubstrateLoad, 2, value));
            BindIoName("LG.SubstrateLoad.VacuumOk", value => SetIndicator(State.SubstrateLoad, 3, value));

            BindIoName("LG.ChipLoad.SensorIn", value => SetIndicator(State.ChipLoad, 0, value));
            BindIoName("LG.ChipLoad.TrackMotorRun", value => SetIndicator(State.ChipLoad, 1, value));
            BindIoName("LG.ChipLoad.HomeChecked", value => SetIndicator(State.ChipLoad, 2, value));
            BindIoName("LG.ChipLoad.VacuumOk", value => SetIndicator(State.ChipLoad, 3, value));

            BindIoName("LG.SubstrateOut.SensorIn", value => SetIndicator(State.SubstrateOut, 0, value));
            BindIoName("LG.SubstrateOut.TrackMotorRun", value => SetIndicator(State.SubstrateOut, 1, value));
            BindIoName("LG.SubstrateOut.HomeChecked", value => SetIndicator(State.SubstrateOut, 2, value));
            BindIoName("LG.SubstrateOut.VacuumOk", value => SetIndicator(State.SubstrateOut, 3, value));

            BindIoName("LG.ChipUnload.SensorIn", value => SetIndicator(State.ChipUnload, 0, value));
            BindIoName("LG.ChipUnload.TrackMotorRun", value => SetIndicator(State.ChipUnload, 1, value));
            BindIoName("LG.ChipUnload.HomeChecked", value => SetIndicator(State.ChipUnload, 2, value));
            BindIoName("LG.ChipUnload.VacuumOk", value => SetIndicator(State.ChipUnload, 3, value));

            BindIoId(1001, value => SetIndicator(State.SubstrateLoad, 0, value));
            BindIoId(1002, value => SetIndicator(State.SubstrateLoad, 1, value));
            BindIoId(1003, value => SetIndicator(State.SubstrateLoad, 2, value));
            BindIoId(1004, value => SetIndicator(State.SubstrateLoad, 3, value));
        }

        private void BindIoName(string name, Action<bool> setter)
        {
            _ioNameBindings[name] = setter;
        }

        private void BindIoId(int id, Action<bool> setter)
        {
            _ioIdBindings[id] = setter;
        }

        private void OnIoSnapshotChanged(object sender, DeviceIoChangedEventArgs e)
        {
            var changedPoints = e.ChangedPoints;
            for (var i = 0; i < changedPoints.Count; i++)
            {
                ApplyIoPoint(changedPoints[i]);
            }
        }

        private void ApplyIoPoint(DeviceIoPointState point)
        {
            if (point == null)
            {
                return;
            }

            Action<bool> setter;
            if (!string.IsNullOrWhiteSpace(point.Name) && _ioNameBindings.TryGetValue(point.Name, out setter))
            {
                setter(point.Value);
                return;
            }

            if (_ioIdBindings.TryGetValue(point.Id, out setter))
            {
                setter(point.Value);
            }
        }

        private void RequestIoRefresh()
        {
            _ioMonitorService.RequestRefresh();
        }

        private static void SetIndicator(SectionState section, int index, bool isOn)
        {
            if (section == null || section.Indicators.Count <= index)
            {
                return;
            }

            section.Indicators[index].IsOn = isOn;
        }
    }
}
