using System;
using System.Threading.Tasks;
using Serilog;
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
using ShareeBike.Model.Connector;
using ShareeBike.Model.Device;
using ShareeBike.Model.User;
using ShareeBike.MultilingualResources;
using ShareeBike.Repository.Exception;
using ShareeBike.View;

namespace ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler
{
	using IRequestHandler = BluetoothLock.IRequestHandler;

	public class BookedOpen : Base, IRequestHandler

	{
		/// <param name="smartDevice">Provides info about the smart device (phone, tablet, ...)</param>
		/// <param name="bikesViewModel">View model to be used for progress report and unlocking/ locking view.</param>
		public BookedOpen(
		   IBikeInfoMutable selectedBike,
		   Func<bool> isConnectedDelegate,
		   Func<bool, IConnector> connectorFactory,
		   Func<IPollingUpdateTaskManager> viewUpdateManager,
		   ISmartDevice smartDevice,
		   IViewService viewService,
		   IBikesViewModel bikesViewModel,
		   IUser activeUser) : base(
			   selectedBike,
			   nameof(BookedOpen),
			   false, // Lock can only be closed manually and returning is performed by placing bike into the station.
			   isConnectedDelegate,
			   connectorFactory,
			   viewUpdateManager,
			   smartDevice,
			   viewService,
			   bikesViewModel,
			   activeUser)
		{
			LockitButtonText = AppResources.ActionOpenLock; // Lock is open but show button anyway to be less prone to errors.
			IsLockitButtonVisible = true;
		}

		/// <summary> Close lock and return bike.</summary>
		public async Task<IRequestHandler> HandleRequestOption1() => await UnsupportedRequest();

		/// <summary> Close lock in order to pause ride and update COPRI lock state.</summary>
		public async Task<IRequestHandler> HandleRequestOption2() => await OpenLock();

		/// <summary> Request is not supported, button should be disabled. </summary>
		public async Task<IRequestHandler> UnsupportedRequest()
		{
			Log.ForContext<BookedOpen>().Error("Click of unsupported button click detected.");
			return await Task.FromResult<IRequestHandler>(this);
		}

		/// <summary> Open bike. </summary>
		public async Task<IRequestHandler> OpenLock()
		{
			// Unlock bike.
			Log.ForContext<BookedOpen>().Information("User request to unlock bike {bike}. For locking state {state} this request is unexpected.", SelectedBike, SelectedBike?.LockInfo?.State);

			// Stop polling before returning bike.
			BikesViewModel.IsIdle = false;
			BikesViewModel.ActionText = AppResources.ActivityTextOneMomentPlease;
			await ViewUpdateManager().StopAsync();

			BikesViewModel.ActionText = AppResources.ActivityTextOpeningCopriLock;
			IsConnected = IsConnectedDelegate();
			try
			{
				await ConnectorFactory(IsConnected).Command.OpenLockAsync(SelectedBike);
			}
			catch (Exception exception)
			{
				BikesViewModel.ActionText = string.Empty;

				if (exception is WebConnectFailureException)
				{
					// Copri server is not reachable.
					Log.ForContext<BookedOpen>().Information("User selected bike {id} but opening lock failed (Copri server not reachable).", SelectedBike.Id);

					await ViewService.DisplayAlert(
						AppResources.ErrorNoConnectionTitle,
						AppResources.ErrorNoWeb,
						AppResources.MessageAnswerOk);
				}
				else
				{
					Log.ForContext<BookedOpen>().Error("Lock can not be opened. {Exception}", exception);

					await ViewService.DisplayAlert(
						AppResources.ErrorOpenLockTitle,
						exception.Message,
						AppResources.MessageAnswerOk);
				}

				BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
				await ViewUpdateManager().StartAsync();
				BikesViewModel.ActionText = string.Empty;
				BikesViewModel.IsIdle = true;
				return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
			}

			Log.ForContext<BookedOpen>().Information("User paused ride using {bike} successfully.", SelectedBike);
			BikesViewModel.ActionText = AppResources.ActivityTextStartingUpdater;
			await ViewUpdateManager().StartAsync();
			BikesViewModel.ActionText = string.Empty;
			BikesViewModel.IsIdle = true;
			return RequestHandlerFactory.Create(SelectedBike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser);
		}
	}
}