using MainShell.ProcessResult;
using MainShell.Recipe.Models;
using System;

namespace MainShell.Process
{
    public class AutoProductionRuntimeStateService
    {
        private readonly ProcessResultManager _processResultManager;

        public AutoProductionRuntimeStateService(ProcessResultManager processResultManager)
        {
            _processResultManager = processResultManager ?? throw new ArgumentNullException(nameof(processResultManager));
        }

        public int CurrentSubstratePendingCount
        {
            get { return _processResultManager.AutoProductionRuntimeState.CurrentSubstratePendingCount; }
        }

        public int CurrentSubstrateProcessedCount
        {
            get { return _processResultManager.AutoProductionRuntimeState.CurrentSubstrateProcessedCount; }
        }

        public int CurrentChipRemainingCount
        {
            get { return _processResultManager.AutoProductionRuntimeState.CurrentChipRemainingCount; }
        }

        public bool TransferNeedsRecheck
        {
            get { return _processResultManager.AutoProductionRuntimeState.TransferNeedsRecheck; }
        }

        public bool TransferChipExhausted
        {
            get { return _processResultManager.AutoProductionRuntimeState.TransferChipExhausted; }
        }

        public void PrepareForRun(RecipeManager recipeManager, CurrentChipLifecycleState currentChipState, bool isResume)
        {
            if (isResume)
            {
                return;
            }

            int defaultSubstrateTargetCount = ResolveDefaultSubstrateTargetCount(recipeManager);
            AutoProductionRuntimeState runtimeState = CloneState();

            runtimeState.CurrentSubstratePendingCount = Math.Max(0, defaultSubstrateTargetCount);
            runtimeState.CurrentSubstrateProcessedCount = 0;

            if (currentChipState == CurrentChipLifecycleState.Empty)
            {
                runtimeState.CurrentChipRemainingCount = 0;
            }
            else
            {
                runtimeState.CurrentChipRemainingCount = 1;
            }

            runtimeState.TransferNeedsRecheck = false;
            runtimeState.TransferChipExhausted = false;
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.DashboardState.PendingCount = runtimeState.CurrentSubstratePendingCount;
            _processResultManager.DashboardState.ProcessedCount = runtimeState.CurrentSubstrateProcessedCount;
            _processResultManager.SaveDashboardState();
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
        }

        public bool ConsumeSubstrateTarget()
        {
            AutoProductionRuntimeState runtimeState = CloneState();
            if (runtimeState.CurrentSubstratePendingCount <= 0)
            {
                return true;
            }

            runtimeState.CurrentSubstratePendingCount = Math.Max(0, runtimeState.CurrentSubstratePendingCount - 1);
            runtimeState.CurrentSubstrateProcessedCount = runtimeState.CurrentSubstrateProcessedCount + 1;
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.DashboardState.PendingCount = runtimeState.CurrentSubstratePendingCount;
            _processResultManager.DashboardState.ProcessedCount = runtimeState.CurrentSubstrateProcessedCount;
            _processResultManager.SaveDashboardState();
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
            return runtimeState.CurrentSubstratePendingCount == 0;
        }

        public bool ConsumeCurrentChip()
        {
            AutoProductionRuntimeState runtimeState = CloneState();
            if (runtimeState.CurrentChipRemainingCount <= 0)
            {
                return false;
            }

            runtimeState.CurrentChipRemainingCount = Math.Max(0, runtimeState.CurrentChipRemainingCount - 1);
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
            return runtimeState.CurrentChipRemainingCount == 0;
        }

        public bool ConsumeTransferNeedsRecheck()
        {
            if (!_processResultManager.AutoProductionRuntimeState.TransferNeedsRecheck)
            {
                return false;
            }

            AutoProductionRuntimeState runtimeState = CloneState();
            runtimeState.TransferNeedsRecheck = false;
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
            return true;
        }

        public bool ConsumeTransferChipExhausted()
        {
            if (!_processResultManager.AutoProductionRuntimeState.TransferChipExhausted)
            {
                return false;
            }

            AutoProductionRuntimeState runtimeState = CloneState();
            runtimeState.TransferChipExhausted = false;
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
            return true;
        }

        public void SetCurrentChipRemainingCount(int remainingCount)
        {
            AutoProductionRuntimeState runtimeState = CloneState();
            runtimeState.CurrentChipRemainingCount = Math.Max(0, remainingCount);
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
        }

        public void MarkTransferNeedsRecheck()
        {
            AutoProductionRuntimeState runtimeState = CloneState();
            runtimeState.TransferNeedsRecheck = true;
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
        }

        public void MarkTransferChipExhausted()
        {
            AutoProductionRuntimeState runtimeState = CloneState();
            runtimeState.TransferChipExhausted = true;
            runtimeState.LastUpdatedTime = DateTime.Now;
            _processResultManager.SaveAutoProductionRuntimeState(runtimeState);
        }

        private AutoProductionRuntimeState CloneState()
        {
            AutoProductionRuntimeState source = _processResultManager.AutoProductionRuntimeState;
            return new AutoProductionRuntimeState
            {
                CurrentSubstratePendingCount = source.CurrentSubstratePendingCount,
                CurrentSubstrateProcessedCount = source.CurrentSubstrateProcessedCount,
                CurrentChipRemainingCount = source.CurrentChipRemainingCount,
                TransferNeedsRecheck = source.TransferNeedsRecheck,
                TransferChipExhausted = source.TransferChipExhausted,
                LastUpdatedTime = source.LastUpdatedTime
            };
        }

        private static int ResolveDefaultSubstrateTargetCount(RecipeManager recipeManager)
        {
            if (recipeManager == null || recipeManager.CurrentSubstrateRecipe == null || recipeManager.CurrentSubstrateRecipe.SubstrateInfo == null)
            {
                return 0;
            }

            int rowNumber = Math.Max(0, recipeManager.CurrentSubstrateRecipe.SubstrateInfo.RowNumber);
            int colNumber = Math.Max(0, recipeManager.CurrentSubstrateRecipe.SubstrateInfo.ColNumber);
            if (rowNumber == 0 || colNumber == 0)
            {
                return 0;
            }

            return rowNumber * colNumber;
        }
    }
}