using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GreenTree.Nachtragsmanagement.Core.Data;
using GreenTree.Nachtragsmanagement.Core.Domain.Deviation;

namespace GreenTree.Nachtragsmanagement.Services.Deviation
{
    public class DeviationService : IDeviationService
    {
        #region Fields

        private readonly IRepository<Core.Domain.Deviation.Deviation> _deviationRepository;
        private readonly IRepository<Disturbance> _disturbanceRepository;
        private readonly IRepository<Kind> _kindRepository;
        private readonly IRepository<Status> _statusRepository;

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes a new instance of the DeviationService class
        /// </summary>
        public DeviationService(
            IRepository<Core.Domain.Deviation.Deviation> deviationRepository,
            IRepository<Disturbance> disturbanceRepository,
            IRepository<Kind> kindRepository,
            IRepository<Status> statusRepository)
        {
            _deviationRepository = deviationRepository;
            _disturbanceRepository = disturbanceRepository;
            _kindRepository = kindRepository;
            _statusRepository = statusRepository;
        }

        #endregion

        #region Deviation

        /// <summary>
        /// Gets all deviations
        /// </summary>
        public IList<Core.Domain.Deviation.Deviation> GetAllDeviations()
        {
            return _deviationRepository.Table.ToList();
        }

        /// <summary>
        /// Gets all deviations where the user is assigned to the corresponding site if the current role only allows assigned sites
        /// </summary>
        public IList<Core.Domain.Deviation.Deviation> GetAllUserAssignedDeviations(Core.Domain.User.User user)
        {
            if (user == null || (user != null && user.CurrentRole == null))
                return new List<Core.Domain.Deviation.Deviation>();

            if (user.CurrentRole.SeeOnlyAssigned)
            {
                return
                    _deviationRepository.Table
                        .Where(d => 
                            (d.Site != null && d.Site.Users
                                .Select(u => u.Id).Contains(user.Id)) ||
                            (d.Appendix != null && d.Appendix.Site != null && d.Appendix.Site.Users
                                .Select(u => u.Id).Contains(user.Id)))
                        .ToList();
            }
            else
                return GetAllDeviations();

        }

        /// <summary>
        /// Gets a deviation by specified Id
        /// </summary>
        /// <param name="id">Deviation identifier.</param>
        public Core.Domain.Deviation.Deviation GetDeviationById(int id)
        {
            return _deviationRepository.GetById(id);
        }

        /// <summary>
        /// Gets all deviations to the specified ids
        /// </summary>
        public IList<Core.Domain.Deviation.Deviation> GetDeviationsByIds(int[] ids)
        {
            return _deviationRepository.Table
                .Where(u => ids.Contains(u.Id))
                .ToList();
        }

        /// <summary>
        /// Gets a deviation by specified custom number
        /// </summary>
        /// <param name="customNumber">Customer number.</param>
        public Core.Domain.Deviation.Deviation GetDeviationByCustomNumber(string customNumber)
        {
            return _deviationRepository
                .Table.FirstOrDefault(u => u.CustomNumber == customNumber);
        }

        /// <summary>
        /// Insert a deviation
        /// </summary>
        /// <param name="deviation">Deviation.</param>
        public void InsertDeviation(Core.Domain.Deviation.Deviation deviation)
        {
            _deviationRepository.Insert(deviation);
        }

        /// <summary>
        /// Update a deviation
        /// </summary>
        /// <param name="deviation">Deviation.</param>
        public void UpdateDeviation(Core.Domain.Deviation.Deviation deviation)
        {
            _deviationRepository.Update(deviation);
        }

        /// <summary>
        /// Delete a deviation
        /// </summary>
        /// <param name="deviation">Deviation.</param>
        public void DeleteDeviation(Core.Domain.Deviation.Deviation deviation)
        {
            _deviationRepository.Delete(deviation);
        }

        #endregion

        #region Disturbance

        /// <summary>
        /// Gets all disturbances
        /// </summary>
        public IList<Disturbance> GetAllDisturbances()
        {
            return _disturbanceRepository.Table.ToList();
        }

        /// <summary>
        /// Gets a disturbance by specified Id
        /// </summary>
        /// <param name="id">Disturbance identifier.</param>
        public Disturbance GetDisturbanceById(int id)
        {
            return _disturbanceRepository.GetById(id);
        }

        /// <summary>
        /// Gets all disturbances to the specified ids
        /// </summary>
        public IList<Disturbance> GetDisturbancesByIds(int[] ids)
        {
            return _disturbanceRepository.Table
                .Where(r => ids.Contains(r.Id))
                .ToList();
        }

        /// <summary>
        /// Insert a deviation
        /// </summary>
        /// <param name="disturbance">Disturbance.</param>
        public void InsertDisturbance(Disturbance disturbance)
        {
            _disturbanceRepository.Insert(disturbance);
        }

        /// <summary>
        /// Update a disturbance
        /// </summary>
        /// <param name="disturbance">Disturbance.</param>
        public void UpdateDisturbance(Disturbance disturbance)
        {
            _disturbanceRepository.Update(disturbance);
        }

        /// <summary>
        /// Delete a disturbance
        /// </summary>
        /// <param name="disturbance">Disturbance.</param>
        public void DeleteDisturbance(Disturbance disturbance)
        {
            _disturbanceRepository.Delete(disturbance);
        }

        #endregion

        #region Kind

        /// <summary>
        /// Gets all kinds
        /// </summary>
        public IList<Kind> GetAllKinds()
        {
            return _kindRepository.Table.ToList();
        }

        /// <summary>
        /// Gets a kind by specified Id
        /// </summary>
        /// <param name="id">Kind identifier.</param>
        public Kind GetKindById(int id)
        {
            return _kindRepository.GetById(id);
        }

        /// <summary>
        /// Gets all kinds to the specified ids
        /// </summary>
        public IList<Kind> GetKindsByIds(int[] ids)
        {
            return _kindRepository.Table
                .Where(r => ids.Contains(r.Id))
                .ToList();
        }

        /// <summary>
        /// Gets all deviations to the specified with the specified kind id
        /// </summary>
        /// <param name="id">Kind identifier.</param>
        public IList<Core.Domain.Deviation.Deviation> GetDeviationsByKind(int id)
        {
            return _deviationRepository.Table
                .Where(d => d.KindId == id)
                .ToList();
        }

        /// <summary>
        /// Gets the kind which is defaultly selected
        /// </summary>
        public Kind GetDefaultKind()
        {
            return _kindRepository.Table
                .FirstOrDefault(k => k.IsDefault);
        }

        /// <summary>
        /// Insert a kind
        /// </summary>
        /// <param name="kind">Kind.</param>
        public void InsertKind(Kind kind)
        {
            _kindRepository.Insert(kind);
        }

        /// <summary>
        /// Update a kind
        /// </summary>
        /// <param name="kind">Kind.</param>
        public void UpdateKind(Kind kind)
        {
            _kindRepository.Update(kind);
        }

        /// <summary>
        /// Delete a kind
        /// </summary>
        /// <param name="kind">Kind.</param>
        public void DeleteKind(Kind kind)
        {
            _kindRepository.Delete(kind);
        }

        #endregion

        #region Status

        /// <summary>
        /// Gets all statuses
        /// </summary>
        public IList<Status> GetAllStatuses()
        {
            return _statusRepository.Table.ToList();
        }

        /// <summary>
        /// Gets a status by specified Id
        /// </summary>
        /// <param name="id">Status identifier.</param>
        public Status GetStatusById(int id)
        {
            return _statusRepository.GetById(id);
        }

        /// <summary>
        /// Gets all statuses to the specified ids
        /// </summary>
        public IList<Status> GetStatusesByIds(int[] ids)
        {
            return _statusRepository.Table
                .Where(r => ids.Contains(r.Id))
                .ToList();
        }

        /// <summary>
        /// Gets all deviations to the specified with the specified status id
        /// </summary>
        /// <param name="id">Status identifier.</param>
        public IList<Core.Domain.Deviation.Deviation> GetDeviationsByStatus(int id)
        {
            return _deviationRepository.Table
                .Where(d => d.StatusId == id)
                .ToList();
        }

        /// <summary>
        /// Gets the status which is defaultly selected
        /// </summary>
        public Status GetDefaultStatus()
        {
            return _statusRepository.Table
                .FirstOrDefault(s => s.IsDefault);
        }

        /// <summary>
        /// Insert a status
        /// </summary>
        /// <param name="status">Status.</param>
        public void InsertStatus(Status status)
        {
            _statusRepository.Insert(status);
        }

        /// <summary>
        /// Update a status
        /// </summary>
        /// <param name="status">Status.</param>
        public void UpdateStatus(Status status)
        {
            _statusRepository.Update(status);
        }

        /// <summary>
        /// Delete a status
        /// </summary>
        /// <param name="status">Status.</param>
        public void DeleteStatus(Status status)
        {
            _statusRepository.Delete(status);
        }

        #endregion
    }
}