using MainShell.Common;
using MainShell.Hardware;
using MainShell.Manual.Model;
using MainShell.Process;
using MainShell.ProcessResult;
using MainShell.Recipe.Models;
using MainShell.Recipe.Models.SubstrateParameter;
using MW.WorkFlow;
using Stylet;
using StyletIoC;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;

namespace MainShell.Manual.ViewModel
{
    public class SubstrateHeightMeasureDisplayItem : PropertyChangedBase
    {
        private string _pointName;
        public string PointName
        {
            get { return _pointName; }
            set { SetAndNotify(ref _pointName, value); }
        }

        private int _rowIndex;
        public int RowIndex
        {
            get { return _rowIndex; }
            set { SetAndNotify(ref _rowIndex, value); }
        }

        private int _columnIndex;
        public int ColumnIndex
        {
            get { return _columnIndex; }
            set { SetAndNotify(ref _columnIndex, value); }
        }

        private double _positionX;
        public double PositionX
        {
            get { return _positionX; }
            set { SetAndNotify(ref _positionX, value); }
        }

        private double _positionY;
        public double PositionY
        {
            get { return _positionY; }
            set { SetAndNotify(ref _positionY, value); }
        }

        private double? _heightValue;
        public double? HeightValue
        {
            get { return _heightValue; }
            set { SetAndNotify(ref _heightValue, value); }
        }
    }

    public class SubstrateHeightMeasureViewModel : OperateViewModelBase
    {
        private readonly IEventAggregator _eventAggregator;
        private readonly RecipeManager _recipeManager;
        private readonly ProcessResultManager _processResultManager;
        private readonly SubstrateHeightMeasureService _substrateHeightMeasureService;

        private ObservableCollection<SubstrateHeightMeasureDisplayItem> _pointResults = new ObservableCollection<SubstrateHeightMeasureDisplayItem>();
        public ObservableCollection<SubstrateHeightMeasureDisplayItem> PointResults
        {
            get { return _pointResults; }
            set { SetAndNotify(ref _pointResults, value); }
        }

        private string _recipeName;
        public string RecipeName
        {
            get { return _recipeName; }
            set { SetAndNotify(ref _recipeName, value); }
        }

        private int _configuredPointCount;
        public int ConfiguredPointCount
        {
            get { return _configuredPointCount; }
            set { SetAndNotify(ref _configuredPointCount, value); }
        }

        private int _measuredPointCount;
        public int MeasuredPointCount
        {
            get { return _measuredPointCount; }
            set { SetAndNotify(ref _measuredPointCount, value); }
        }

        private SubstrateHeightMeasureMode _currentMeasureMode;
        public SubstrateHeightMeasureMode CurrentMeasureMode
        {
            get { return _currentMeasureMode; }
            set { SetAndNotify(ref _currentMeasureMode, value); }
        }

        public SubstrateHeightMeasureViewModel(
            IEventAggregator eventAggregator,
            RecipeManager recipeManager,
            ProcessResultManager processResultManager,
            HardwareManager hardwareManager,
            SubstrateHeightMeasureService substrateHeightMeasureService)
        {
            _eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
            _recipeManager = recipeManager ?? throw new ArgumentNullException(nameof(recipeManager));
            _processResultManager = processResultManager ?? throw new ArgumentNullException(nameof(processResultManager));
            _substrateHeightMeasureService = substrateHeightMeasureService ?? throw new ArgumentNullException(nameof(substrateHeightMeasureService));

            _cameraAxisViewModel = IoC.Get<Common.Display.ViewModel.CameraAxisViewModel>();
            _cameraAxisViewModel.CameraAxisDevices.HardwareDeviceList = hardwareManager.CameraAxisManager.TopCameraAxisDevices;

            RefreshRecipeSummary();
            LoadLastMeasureResult();
        }

        protected override void OnViewLoaded()
        {
            base.OnViewLoaded();
            RefreshRecipeSummary();
            LoadLastMeasureResult();
        }

        public async Task StartProcess()
        {
            RefreshRecipeSummary();

            WorkflowContext context = new WorkflowContext();
            context[WorkflowContextKeys.EventAggregator] = _eventAggregator;
            context[WorkflowContextKeys.RecipeManager] = _recipeManager;
            context[WorkflowContextKeys.ProcessResultManager] = _processResultManager;
            context[WorkflowContextKeys.WorkflowName] = ProcessFlowName.SubstrateHeightMeasureFlow;

            WorkflowRunCompletedEventArgs result = await RunManualActivityAsync(
                new SubstrateHeightMeasureActivity(ProcessFlowName.SubstrateHeightMeasureFlow, _substrateHeightMeasureService),
                context);

            if (!IsWorkflowCompleted(result))
            {
                return;
            }

            LoadLastMeasureResult();
        }

        private void RefreshRecipeSummary()
        {
            SubstrateRecipe currentRecipe = _recipeManager.CurrentSubstrateRecipe;
            RecipeName = currentRecipe == null ? string.Empty : currentRecipe.RecipeName;

            if (currentRecipe == null || currentRecipe.HeightMeasureSetting == null)
            {
                ConfiguredPointCount = 0;
                CurrentMeasureMode = SubstrateHeightMeasureMode.StandardTeachPosition;
                return;
            }

            ConfiguredPointCount = currentRecipe.HeightMeasureSetting.Points == null ? 0 : currentRecipe.HeightMeasureSetting.Points.Count;
            CurrentMeasureMode = currentRecipe.HeightMeasureSetting.Mode;
        }

        private void LoadLastMeasureResult()
        {
            PointResults.Clear();

            SubstrateHeightMeasureProcessResult processResult = _processResultManager.SubstrateHeightMeasureResult;
            if (processResult == null || processResult.PointResults == null)
            {
                MeasuredPointCount = 0;
                return;
            }

            foreach (SubstrateHeightMeasurePointResult pointResult in processResult.PointResults)
            {
                PointResults.Add(new SubstrateHeightMeasureDisplayItem
                {
                    PointName = pointResult.PointName,
                    RowIndex = pointResult.RowIndex,
                    ColumnIndex = pointResult.ColumnIndex,
                    PositionX = pointResult.PositionX,
                    PositionY = pointResult.PositionY,
                    HeightValue = pointResult.HeightValue
                });
            }

            MeasuredPointCount = PointResults.Count;
        }
    }
}
