using MainShell.Common;
using MainShell.Hardware;
using MainShell.Manual.Model;
using MainShell.Models;
using MainShell.Process;
using MainShell.ProcessResult;
using MainShell.Recipe.Models;
using MainShell.Resources.CustomControl;
using MaxwellFramework.Core.Interfaces;
using Stylet;
using System;
using System.Threading.Tasks;

namespace MainShell.Manual.ViewModel
{
    public class DieStatisticsModel : PropertyChangedBase
    {
        private int _totalDieCount;
        public int TotalDieCount
        {
            get => _totalDieCount;
            set
            {
                if (SetAndNotify(ref _totalDieCount, value))
                {
                    UpdatePassRate();
                }
            }
        }

        private int _okDieCount;
        public int OkDieCount
        {
            get => _okDieCount;
            set
            {
                if (SetAndNotify(ref _okDieCount, value))
                {
                    UpdatePassRate();
                }
            }
        }

        private int _ngDieCount;
        public int NgDieCount
        {
            get => _ngDieCount;
            set => SetAndNotify(ref _ngDieCount, value);
        }

        private double _averageSpacingX;
        public double AverageSpacingX
        {
            get => _averageSpacingX;
            set => SetAndNotify(ref _averageSpacingX, value);
        }

        private double _averageSpacingY;
        public double AverageSpacingY
        {
            get => _averageSpacingY;
            set => SetAndNotify(ref _averageSpacingY, value);
        }

        private double _passRate;
        public double PassRate
        {
            get => _passRate;
            private set => SetAndNotify(ref _passRate, value);
        }

        private void UpdatePassRate()
        {
            PassRate = TotalDieCount > 0 ? (double)OkDieCount / TotalDieCount * 100 : 0;
        }
    }

    public class DiePositionViewModel : OperateViewModelBase
    {
        private readonly RecipeManager _recipeManager;
        private readonly IEventAggregator _eventAggregator;
        private readonly ProcessResultManager _processResultManager;
        private readonly HardwareManager _hardwareManager;
        private readonly DiePositionService _diePositionService;

        private DieStatisticsModel _statistics = new DieStatisticsModel();
        public DieStatisticsModel Statistics
        {
            get => _statistics;
            set => SetAndNotify(ref _statistics, value);
        }

        private DieMapModel _dieMapModel = new DieMapModel();
        public DieMapModel DieMapModel
        {
            get => _dieMapModel;
            set => SetAndNotify(ref _dieMapModel, value);
        }

        public DiePositionViewModel(
            IEventAggregator eventAggregator,
            RecipeManager recipeManager,
            ProcessResultManager processResultManager,
            HardwareManager hardwareManager,
            IParameterManager parameterManager,
            DiePositionService diePositionService)
        {
            _eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
            _recipeManager = recipeManager ?? throw new ArgumentNullException(nameof(recipeManager));
            _processResultManager = processResultManager ?? throw new ArgumentNullException(nameof(processResultManager));
            _hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
            _diePositionService = diePositionService ?? throw new ArgumentNullException(nameof(diePositionService));

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

            InitTestMap();
        }

        private void InitTestMap()
        {
            DieMapModel.Initialize(3, 3);

            for (int r = 0; r < 3; r++)
            {
                for (int c = 0; c < 3; c++)
                {
                    DieMapModel.SetDieState(r, c, DieState.Available);
                }
            }

            DieMapModel.SetDieState(1, 1, DieState.Current);
        }

        public async Task StartProcess()
        {
            MW.WorkFlow.WorkflowContext context = new MW.WorkFlow.WorkflowContext();
            context[WorkflowContextKeys.EventAggregator] = _eventAggregator;
            context[WorkflowContextKeys.RecipeManager] = _recipeManager;
            context[WorkflowContextKeys.ProcessResultManager] = _processResultManager;
            context[WorkflowContextKeys.WorkflowName] = ProcessFlowName.DiePositionFlow;

            var result = await RunManualActivityAsync(
                new DiePositionActivity(ProcessFlowName.DiePositionFlow, _diePositionService),
                context);

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

            DiePositionProcessResult processResult = context.GetData<DiePositionProcessResult>(WorkflowContextKeys.DiePositionResult);
            if (processResult == null)
            {
                return;
            }

            UpdateStatistics(processResult);
            UpdateMap(processResult);
        }

        private void UpdateStatistics(DiePositionProcessResult processResult)
        {
            Statistics.TotalDieCount = processResult.TheoryDieCount;
            Statistics.OkDieCount = processResult.RecognizedDieCount;
            Statistics.NgDieCount = processResult.NgDieCount;
            Statistics.AverageSpacingX = processResult.AverageSpacingX;
            Statistics.AverageSpacingY = processResult.AverageSpacingY;
        }

        private void UpdateMap(DiePositionProcessResult processResult)
        {
            if (processResult.RowCount <= 0 || processResult.ColumnCount <= 0)
            {
                return;
            }

            DieMapModel.Initialize(processResult.RowCount, processResult.ColumnCount);
            DieMapModel.SetDieState(0, 0, DieState.Current);
        }
    }
}