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

namespace skydiveLogs_api.DomainBusiness
{
    public class StatsService : IStatsService
    {
        #region Public Constructors

        public StatsService(IJumpService jumpService,
                            IUserStatsRepository userStatsRepository,
                            IIdentityService identityService)
        {
            _jumpService = jumpService;
            _identityService = identityService;
            _userStatsRepository = userStatsRepository;
        }

        #endregion Public Constructors

        #region Public Methods

        public SimpleSummary GetSimpleSummary()
        {
            var allJumps = _jumpService.GetAllJumps();
            var results = new SimpleSummary();

            if (allJumps.Any())
            {
                var lastJump = allJumps.OrderByDescending(j => j.JumpDate).First();

                results = new SimpleSummary
                {
                    LastJump = lastJump,
                    TotalJumps = allJumps.Count(),
                    TotalCutaways = allJumps.Where(j => j.WithCutaway).Count()
                };
            }

            return results;
        }

        public IEnumerable<Statistic> GetStatsByAircraft()
        {
            var allStats = GetAllStats();
            if (!allStats.ByAircraft.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    results = allJumps.GroupBy(j => j.Aircraft.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ByAircraft = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ByAircraft;
        }

        public IEnumerable<Statistic> GetStatsByDz()
        {
            var allStats = GetAllStats();
            if (!allStats.ByDz.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    results = allJumps.GroupBy(j => j.DropZone.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ByDz = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ByDz;
        }

        public IEnumerable<Statistic> GetStatsByGear()
        {
            var allStats = GetAllStats();
            if (!allStats.ByGear.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    results = allJumps.GroupBy(j => $"{j.Gear.Name} / {j.Gear.MainCanopy}",
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ByGear = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ByGear;
        }

        public IEnumerable<Statistic> GetStatsByJumpType()
        {
            var allStats = GetAllStats();
            if (!allStats.ByJumpType.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    results = allJumps.GroupBy(j => j.JumpType.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ByJumpType = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ByJumpType;
        }

        public IEnumerable<Statistic> GetStatsByYear()
        {
            var allStats = GetAllStats();
            if (!allStats.ByYear.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    results = allJumps.GroupBy(j => j.JumpDate.Year,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ByYear = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ByYear;
        }

        public IEnumerable<Statistic> GetStatsForLastMonthByDz()
        {
            var allStats = GetAllStats();
            if (!allStats.ForLastMonthByDz.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    var lastJump = allJumps.OrderByDescending(j => j.JumpDate).First();
                    var yearOfLastJump = lastJump.JumpDate.Year;
                    var monthOfLastJump = lastJump.JumpDate.Month;

                    results = allJumps.Where(j => j.JumpDate.Year == yearOfLastJump && j.JumpDate.Month == monthOfLastJump)
                                      .GroupBy(j => j.DropZone.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ForLastMonthByDz = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ForLastMonthByDz;
        }

        public IEnumerable<Statistic> GetStatsForLastMonthByJumpType()
        {
            var allStats = GetAllStats();
            if (!allStats.ForLastMonthByJumpType.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    var lastJump = allJumps.OrderByDescending(j => j.JumpDate).First();
                    var yearOfLastJump = lastJump.JumpDate.Year;
                    var monthOfLastJump = lastJump.JumpDate.Month;

                    results = allJumps.Where(j => j.JumpDate.Year == yearOfLastJump && j.JumpDate.Month == monthOfLastJump)
                                      .GroupBy(j => j.JumpType.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ForLastMonthByJumpType = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ForLastMonthByJumpType;
        }

        public IEnumerable<Statistic> GetStatsForLastYearByDz()
        {
            var allStats = GetAllStats();
            if (!allStats.ForLastYearByDz.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    var lastJump = allJumps.OrderByDescending(j => j.JumpDate).First();
                    var yearOfLastJump = lastJump.JumpDate.Year;

                    results = allJumps.Where(j => j.JumpDate.Year == yearOfLastJump)
                                      .GroupBy(j => j.DropZone.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ForLastYearByDz = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ForLastYearByDz;
        }

        public IEnumerable<Statistic> GetStatsForLastYearByJumpType()
        {
            var allStats = GetAllStats();
            if (!allStats.ForLastYearByJumpType.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    var lastJump = allJumps.OrderByDescending(j => j.JumpDate).First();
                    var yearOfLastJump = lastJump.JumpDate.Year;

                    results = allJumps.Where(j => j.JumpDate.Year == yearOfLastJump)
                                      .GroupBy(j => j.JumpType.Name,
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ForLastYearByJumpType = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ForLastYearByJumpType;
        }

        public IEnumerable<Statistic> GetStatsByYearByJumpType()
        {
            var allStats = GetAllStats();
            if (!allStats.ByYearByJumpType.Any())
            {
                var allJumps = _jumpService.GetAllJumps();
                var results = new List<Statistic>();

                if (allJumps.Any())
                {
                    results = allJumps.GroupBy(j => new { j.JumpType.Name, j.JumpDate.Year },
                                               j => j,
                                               (groupby, jumps) => new Statistic
                                               {
                                                   Label = groupby.Year.ToString(),
                                                   Label2 = groupby.Name.ToString(),
                                                   Nb = jumps.Count()
                                               })
                                      .ToList();
                }

                allStats.ByYearByJumpType = results;
                _userStatsRepository.Update(allStats);
            }

            return allStats.ByYearByJumpType;
        }

        public void Reset()
        {
            var resetStats = new UserStats();
            var myStats = GetAllStats();
            myStats.ByAircraft = resetStats.ByAircraft;
            myStats.ByDz = resetStats.ByDz;
            myStats.ByGear = resetStats.ByGear;
            myStats.ByJumpType = resetStats.ByJumpType;
            myStats.ByYear = resetStats.ByYear;
            myStats.ForLastMonthByDz = resetStats.ForLastMonthByDz;
            myStats.ForLastMonthByJumpType = resetStats.ForLastMonthByJumpType;
            myStats.ForLastYearByDz = resetStats.ForLastYearByDz;
            myStats.ForLastYearByJumpType = resetStats.ForLastYearByJumpType;

            _userStatsRepository.Update(myStats);
        }

        #endregion Public Methods

        #region Private Methods

        private UserStats GetAllStats()
        {
            var allStats = _userStatsRepository.GetAll(_identityService.ConnectedUser);
            if (allStats == null)
            {
                allStats = new UserStats();
                allStats.User = _identityService.ConnectedUser;
                _userStatsRepository.Add(allStats);
            }

            return allStats;
        }

        #endregion Private Methods

        #region Private Fields

        private readonly IIdentityService _identityService;
        private readonly IJumpService _jumpService;
        private readonly IUserStatsRepository _userStatsRepository;

        #endregion Private Fields
    }
}