using Borepin.Base;
using Prism.Commands;
using Prism.Navigation;
using System.Threading.Tasks;
using System.Windows.Input;
using FabAccessAPI.Schema;
using Borepin.Model;
using Prism.Services;
using Borepin.Service;
using Borepin.Base.Exceptions;
using Capnp.Rpc;
using System;
using Borepin.Service.Browser;
using System.Text;

namespace Borepin.PageModel
{
    public class MachinePageModel : ConnectionModelBase
    {
        #region Private Fields
        private string _ID;
        private Machine _Machine;
        private readonly IBrowserService _BrowserService;
        #endregion

        #region Contructors
        public MachinePageModel(INavigationService navigationService, IPageDialogService pageDialogService, IAPIService apiService, IBrowserService browserService) : base(navigationService, pageDialogService, apiService)
        {
            _BrowserService = browserService;

            UseMachineCommand = new DelegateCommand(UseMachineCommandExecute);
            GiveBackMachineCommand = new DelegateCommand(GiveBackMachineCommandExecute);
            ForceFreeMachineCommand = new DelegateCommand(ForceFreeMachineCommandExecute);
            ForceBlockMachineCommand = new DelegateCommand(ForceBlockMachineCommandExecute);
            ForceDisableMachineCommand = new DelegateCommand(ForceDisableMachineCommandExecute);
            OpenWikiCommand = new DelegateCommand(OpenWikiCommandExecute);
        }
        #endregion

        #region Data
        public override Task LoadInstance(object instance)
        {
            if(instance is string)
            {
                _ID = instance as string;
            }
            else
            {
                throw new InstanceIncorrectException();
            }

            return Task.CompletedTask;
        }

        public override async Task LoadAPIData()
        {
            _Machine = (await _API.Session.MachineSystem.Info.GetMachine(_ID).ConfigureAwait(false)).Just;
            MachineItem = new MachineVisualize(_Machine);
            await MachineItem.LoadData().ConfigureAwait(false);
        }
        #endregion

        #region Fields
        private MachineVisualize _MachineItem;
        public MachineVisualize MachineItem
        {
            get => _MachineItem;
            set => SetProperty(ref _MachineItem, value);
        }
        #endregion

        #region Commands
        private ICommand _UseMachineCommand;

        public ICommand UseMachineCommand
        {
            get => _UseMachineCommand;
            set => SetProperty(ref _UseMachineCommand, value);
        }

        public async void UseMachineCommandExecute()
        {
            IsBusy = true;
            
            if(_API.IsConnected)
            {
                try
                {
                    Machine.IUseInterface useInterface = _Machine.Use;

                    await useInterface.Use().ConfigureAwait(false);
                    await LoadAPIData().ConfigureAwait(false);
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }

        private ICommand _GiveBackMachineCommand;
        public ICommand GiveBackMachineCommand
        {
            get => _GiveBackMachineCommand;
            set => SetProperty(ref _GiveBackMachineCommand, value);
        }

        public async void GiveBackMachineCommandExecute()
        {
            IsBusy = true;

            if (_API.IsConnected)
            {
                try
                {
                    Machine.IInUseInterface inUseInterface = _Machine.Inuse;

                    await inUseInterface.GiveBack().ConfigureAwait(false);
                    await LoadAPIData().ConfigureAwait(false);
                }
                catch(RpcException exception) when(string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }

        private ICommand _ForceFreeMachineCommand;
        public ICommand ForceFreeMachineCommand
        {
            get => _ForceFreeMachineCommand;
            set => SetProperty(ref _ForceFreeMachineCommand, value);
        }

        public async void ForceFreeMachineCommandExecute()
        {
            IsBusy = true;

            if (_API.IsConnected)
            {
                try
                {
                    Machine.IManageInterface manageInterface = _Machine.Manage;

                    await manageInterface.ForceFree().ConfigureAwait(false);
                    await LoadAPIData().ConfigureAwait(false);
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }

        private ICommand _ForceBlockMachineCommand;
        public ICommand ForceBlockMachineCommand
        {
            get => _ForceBlockMachineCommand;
            set => SetProperty(ref _ForceBlockMachineCommand, value);
        }

        public async void ForceBlockMachineCommandExecute()
        {
            IsBusy = true;

            if (_API.IsConnected)
            {
                try
                {
                    Machine.IManageInterface manageInterface = _Machine.Manage;

                    await manageInterface.Block().ConfigureAwait(false);
                    await LoadAPIData().ConfigureAwait(false);
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }

        private ICommand _ForceDisableMachineCommand;
        public ICommand ForceDisableMachineCommand
        {
            get => _ForceDisableMachineCommand;
            set => SetProperty(ref _ForceDisableMachineCommand, value);
        }

        public async void ForceDisableMachineCommandExecute()
        {
            IsBusy = true;

            if (_API.IsConnected)
            {
                try
                {
                    Machine.IManageInterface manageInterface = _Machine.Manage;

                    await manageInterface.Disabled().ConfigureAwait(false);
                    await LoadAPIData().ConfigureAwait(false);
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }

        private ICommand _OpenWikiCommand;
        public ICommand OpenWikiCommand
        {
            get => _OpenWikiCommand;
            set => SetProperty(ref _OpenWikiCommand, value);
        }

        public async void OpenWikiCommandExecute()
        {
            if(_Machine != null && _Machine.Wiki != null)
            {
                try
                {
                    await _BrowserService.OpenAsync(_Machine.Wiki).ConfigureAwait(false);
                }
                catch
                {
                    //TODO: Do something
                }
            }
        }

        private ICommand _UnlockLockCommand;
        public ICommand UnlockLockCommand
        {
            get => _UnlockLockCommand;
            set => SetProperty(ref _UnlockLockCommand, value);
        }

        public async void UnlockLockCommandExecute()
        {
            IsBusy = true;

            if (_API.IsConnected)
            {
                try
                {
                    Machine.IProdInterface prodInterface = _Machine.Prodable;
                    await prodInterface.ProdWithData(Encoding.ASCII.GetBytes("action: unlock")).ConfigureAwait(false);
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }

        private ICommand _IdentifyLockCommand;
        public ICommand IdentifyLockCommand
        {
            get => _IdentifyLockCommand;
            set => SetProperty(ref _IdentifyLockCommand, value);
        }

        public async void IdentifyLockCommandExecute()
        {
            IsBusy = true;

            if (_API.IsConnected)
            {
                try
                {
                    Machine.IProdInterface prodInterface = _Machine.Prodable;
                    await prodInterface.ProdWithData(Encoding.ASCII.GetBytes("action: identify")).ConfigureAwait(false);
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }

            IsBusy = false;
        }
        #endregion
    }
}
