using skydiveLogs_api.Domain;
using skydiveLogs_api.DomainBusiness.Interfaces;
using skydiveLogs_api.DomainService.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;

namespace skydiveLogs_api.DomainBusiness
{
    public class DropZoneService : IDropZoneService
    {
        #region Public Constructors

        public DropZoneService(IDropZoneRepository dropZoneRepository,
                               IFavoriteDropZoneRepository favoriteDropZoneRepository,
                               IIdentityService identityService,
                               ICacheService cacheService)
        {
            _dropZoneRepository = dropZoneRepository;
            _favoriteDropZoneRepository = favoriteDropZoneRepository;
            _identityService = identityService;
            _cacheService = cacheService;
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Adds a new drop zone to the system.
        /// </summary>
        /// <param name="newdropZone">The DropZone entity containing the new drop zone data.</param>
        public void AddNewDz(DropZone newdropZone)
        {
            _dropZoneRepository.Add(newdropZone);
            _cacheService.Delete(CacheType.DropZone);
        }

        /// <summary>
        /// Adds a drop zone to the user's favorites.
        /// </summary>
        /// <param name="dzId">The drop zone ID to add to favorites.</param>
        /// <returns>True if the drop zone was added to favorites, false otherwise.</returns>
        public bool AddToFavorite(int dzId)
        {
            var dzToAddToFavorite = GetDzById(dzId);

            var favoriteDz = new FavoriteDropZone
            {
                DropZone = dzToAddToFavorite,
                User = _identityService.ConnectedUser
            };

            var result = _favoriteDropZoneRepository.Add(favoriteDz);

            return result > 0;
        }

        /// <summary>
        /// Deletes a drop zone by its ID.
        /// </summary>
        /// <param name="id">The drop zone ID to delete.</param>
        public void DeleteDzById(int id)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Retrieves a list of all drop zones with favorites status.
        /// </summary>
        /// <returns>A collection of DropZone entities containing all drop zones with their favorite status.</returns>
        public IEnumerable<DropZone> GetAllDzs()
        {
            var results = Enumerable.Empty<DropZone>();

            var dropzones = GetAllRefDzs();
            var favorites = _favoriteDropZoneRepository.GetAll(_identityService.ConnectedUser);

            results = from dropZone in dropzones
                      join favorite in favorites on dropZone.Id equals favorite.DropZone.Id into tmp
                      from favoriteDz in tmp.DefaultIfEmpty()
                      select new DropZone
                      {
                          Id = dropZone.Id,
                          Address = dropZone.Address,
                          Email = dropZone.Email,
                          Latitude = dropZone.Latitude,
                          Longitude = dropZone.Longitude,
                          Name = dropZone.Name,
                          Type = dropZone.Type,
                          Website = dropZone.Website,
                          IsFavorite = !(favoriteDz == null)
                      };

            return results.ToList();
        }

        /// <summary>
        /// Retrieves a drop zone by its ID.
        /// </summary>
        /// <param name="id">The drop zone ID to retrieve.</param>
        /// <returns>A DropZone entity containing the drop zone details.</returns>
        public DropZone GetDzById(int id)
        {
            var allDzs = GetAllRefDzs();
            return allDzs.Single(g => g.Id == id);
        }

        /// <summary>
        /// Removes a drop zone from the user's favorites.
        /// </summary>
        /// <param name="dzId">The drop zone ID to remove from favorites.</param>
        /// <returns>True if the drop zone was removed from favorites, false otherwise.</returns>
        public bool RemoveToFavorite(int dzId)
        {
            var result = _favoriteDropZoneRepository.Delete(dzId, _identityService.ConnectedUser.Id);
            _cacheService.Delete(CacheType.DropZone);

            return result > 0;
        }

        /// <summary>
        /// Updates an existing drop zone.
        /// </summary>
        /// <param name="id">The drop zone ID to update.</param>
        /// <param name="dropZone">DropZone entity containing the updated drop zone data.</param>
        /// <param name="resetCache">Whether to reset the cache after update.</param>
        /// <returns>True if the update was successful, false otherwise.</returns>
        public bool UpdateDz(int id, DropZone dropZone, bool resetCache = true)
        {
            dropZone.Id = id;

            var result = _dropZoneRepository.Update(dropZone);
            if (resetCache && result)
                _cacheService.Delete(CacheType.DropZone);

            return result;
        }

        private IEnumerable<DropZone> GetAllRefDzs()
        {
            if (!_cacheService.Contains(CacheType.DropZone))
                _cacheService.Put(CacheType.DropZone,
                                  _dropZoneRepository.GetAll(),
                                  5 * 60 * 1000);

            return _cacheService.Get<IEnumerable<DropZone>>(CacheType.DropZone);
        }

        #endregion Public Methods

        #region Private Fields

        private readonly ICacheService _cacheService;
        private readonly IDropZoneRepository _dropZoneRepository;
        private readonly IFavoriteDropZoneRepository _favoriteDropZoneRepository;
        private readonly IIdentityService _identityService;

        #endregion Private Fields
    }
}
