using Serilog;
using System;
using System.Threading;
using System.Threading.Tasks;
using TINK.Model.Device;
using Xamarin.Essentials;

namespace TINK.Model.Services.Geolocation
{
    public class GeolocationService : IGeolocation
    {
        /// <summary> Timeout for geolocation request operations.</summary>
        private const int GEOLOCATIONREQUEST_TIMEOUT_MS = 5000;

        private IGeolodationDependent Dependent { get; }
        
        public GeolocationService(IGeolodationDependent dependent)
        {
            Dependent = dependent;
        }

        public bool IsSimulation => false;

        public bool IsGeolcationEnabled => Dependent.IsGeolcationEnabled;

        /// <summary> Gets the current location.</summary>
        /// <param name="cancellationToken">Token to cancel request for geolocation.</param>
        /// <param name="timeStamp">Time when geolocation is of interest. Is used to determine whether cached geoloation can be used or not.</param>
        public async Task<Location> GetAsync(CancellationToken? cancellationToken = null, DateTime? timeStamp = null)
        {
            try
            {
                var request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromMilliseconds(GEOLOCATIONREQUEST_TIMEOUT_MS));
                return cancellationToken.HasValue
                    ? await Xamarin.Essentials.Geolocation.GetLocationAsync(request, cancellationToken.Value)
                    : await Xamarin.Essentials.Geolocation.GetLocationAsync(request);
            }
            catch (FeatureNotSupportedException fnsEx)
            {
                // Handle not supported on device exception
                Log.ForContext<GeolocationService>().Error("Retrieving Geolocation not supported on device. {Exception}", fnsEx);
                throw new Exception("Abfrage Standort nicht möglich auf Gerät.", fnsEx);
            }
            catch (FeatureNotEnabledException fneEx)
            {
                // Handle not enabled on device exception
                Log.ForContext<GeolocationService>().Error("Retrieving Geolocation not enabled on device. {Exception}", fneEx);
                throw new Exception("Abfrage Standort nicht aktiviert auf Gerät.", fneEx);
            }
            catch (PermissionException pEx)
            {
                // Handle permission exception
                Log.ForContext<GeolocationService>().Error("Retrieving Geolocation not permitted on device. {Exception}", pEx);
                throw new Exception("Berechtiung für Abfrage Standort nicht erteilt für App.", pEx);
            }
            catch (Exception ex)
            {
                // Unable to get location
                Log.ForContext<GeolocationService>().Error("Retrieving Geolocation failed. {Exception}", ex);
                throw new Exception("Abfrage Standort fehlgeschlagen.", ex);
            }
        }
    }
}