using System;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.State;
using TINK.Model.User;
using TINK.View;

namespace TINK.ViewModel.Bikes.Bike.BC.RequestHandler
{
    public abstract class Base<T>
    {
        /// <summary>
        /// View model to be used by subclasses for progress report and unlocking/ locking view.
        /// </summary>
        public IBikesViewModel BikesViewModel { get; set; }

        /// <summary> Gets the bike state. </summary>
        public abstract InUseStateEnum State { get; }

        /// <summary>
        /// Gets a value indicating whether the button to reserve bike is visible or not.
        /// </summary>
        public bool IsButtonVisible { get; }

        /// <summary>
        /// Gets the name of the button when bike is disposable.
        /// </summary>
        public string ButtonText { get; }

        /// <summary> Provides info about the smart device (phone, tablet, ...).</summary>
        protected ISmartDevice SmartDevice;

        /// <summary>
        /// Reference on view service to show modal notifications and to perform navigation.
        /// </summary>
        protected IViewService ViewService { get; }

        /// <summary> Provides a connector object.</summary>
        protected Func<bool, IConnector> ConnectorFactory { get; }

        /// <summary> Delegate to retrieve connected state. </summary>
        protected Func<bool> IsConnectedDelegate { get; }

        /// <summary> Object to manage update of view model objects from Copri.</summary>
        protected Func<IPollingUpdateTaskManager> ViewUpdateManager { get; }

        /// <summary> Reference on the user </summary>
        protected IUser ActiveUser { get; }

        /// <summary> Bike to display. </summary>
        protected T SelectedBike { get; }

        /// <summary>Holds the is connected state. </summary>
        private bool isConnected;

        /// <summary>Gets the is connected state. </summary>
        public bool IsConnected 
        {
            get => isConnected;
            set
            {
                if (value == isConnected)
                    return;

                isConnected = value;
            }
        }

        /// <summary> Gets if the bike has to be remvoed after action has been completed. </summary>
        public bool IsRemoveBikeRequired { get; set; }


        /// <summary>
        /// Constructs the reqest handler base.
        /// </summary>
        /// <param name="selectedBike">Bike which is reserved or for which reservation is canceled.</param>
        /// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...).</param>
        /// <param name="bikesViewModel">View model to be used by subclasses for progress report and unlocking/ locking view.</param>
        public Base(
            T selectedBike,
            string buttonText,
            bool isCopriButtonVisible,
            Func<bool> isConnectedDelegate,
            Func<bool, IConnector> connectorFactory,
            Func<IPollingUpdateTaskManager> viewUpdateManager,
            ISmartDevice smartDevice,
            IViewService viewService,
            IBikesViewModel bikesViewModel,
            IUser activeUser)
        {
            ButtonText = buttonText;
            IsButtonVisible = isCopriButtonVisible;
            SelectedBike = selectedBike;
            IsConnectedDelegate = isConnectedDelegate;
            ConnectorFactory = connectorFactory;
            ViewUpdateManager = viewUpdateManager;
            SmartDevice = smartDevice;
            ViewService = viewService;
            ActiveUser = activeUser;
            IsRemoveBikeRequired = false;
            BikesViewModel = bikesViewModel
                ?? throw new ArgumentException($"Can not construct {GetType().Name}-object. {nameof(bikesViewModel)} must not be null.");
        }
    }
}