using AutoMapper;
using DataAccessLayer;
using DataAccessLayer.Entities;
using DataAccessLayer.Filtering;
using DataAccessLayer.Units;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using WcfServices.Contract;
using WcfServices.Dto;
using WcfServices.Mapping;

namespace WcfServices.Services
{
    public partial class ISService : ITimeSheetRecordService
    {

        [PrincipalPermission(SecurityAction.Demand, Role = "BASIC_ACCESS")]
        public async Task<IEnumerable<TimeSheetRecordDto>> GetTimeSheetRecordsAsync(FilterDto filterDto)
        {
            var retval = new List<TimeSheetRecordDto>();
            using (var timeSheetRecordUnit = new UnitOfWork<TimeSheetRecord>(new ISDbContext()))
            {
                var filter = _mapper.Map<Filter>(filterDto);
                var timeSheetRecords = await timeSheetRecordUnit.GetAsync(filter);

                foreach(var timeSheetRecord in timeSheetRecords)
                {
                    retval.Add(_mapper.Map<TimeSheetRecordDto>(timeSheetRecord));
                }
            }

            return retval;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "BASIC_ACCESS")]
        public async Task GenerateTimeSheetRecordsAsync(int employeeId, int year, int month)
        {
            var filter = BuildAttendanceFilter(employeeId, year, month);
            var attendanceRecords = await this.GetAttendanceRecordsAsync(filter);

            var arrivals = attendanceRecords.Where(x => x.AttendanceEventType.Name == "Příchod");
            var departures = attendanceRecords.Where(x => x.AttendanceEventType.Name == "Odchod");

            var recordsToCreate = new List<TimeSheetRecordDto>();
            foreach (var arrival in arrivals)
            {
                var departure = departures.FirstOrDefault(x => x.TimeStamp.DayOfYear == arrival.TimeStamp.DayOfYear);

                if (departure == null) continue;

                var timeSheetFilter = new FilterDto()
                {
                    Conditions = new List<ConditionItemDto>()
                     {
                          new ConditionItemDto()
                          {
                               Column = nameof(TimeSheetRecord.From),
                               Type = ConditionTypeEnum.Equal,
                               Value = arrival.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss.fff")
                          }
                     }
                };

                var existingTimeSheetRecord = (await this.GetTimeSheetRecordsAsync(timeSheetFilter)).FirstOrDefault();

                var newTimeSheetRecord = new TimeSheetRecordDto()
                {
                    From = arrival.TimeStamp,
                    To = departure.TimeStamp,
                    EmployeeId = employeeId,
                    ProjectId = existingTimeSheetRecord?.ProjectId,
                    Comment = existingTimeSheetRecord?.Comment
                };

                recordsToCreate.Add(newTimeSheetRecord);
            }

            var recordsToDelete = await GetTimeSheetRecordsAsync(BuildTimeSheetFilter(employeeId, year, month));

            foreach (var record in recordsToDelete)
                await DeleteTimeSheetRecordAsync(record.Id);

            foreach (var record in recordsToCreate)
                await CreateTimeSheetRecordAsync(record);


        }

        [PrincipalPermission(SecurityAction.Demand, Role = "BASIC_ACCESS")]
        public async Task<TimeSheetRecordDto> GetTimeSheetRecordByIdAsync(int id)
        {
            TimeSheetRecordDto retval;
            using (var timeSheetRecordUnit = new UnitOfWork<TimeSheetRecord>(new ISDbContext()))
            {
                var timeSheetRecord = await timeSheetRecordUnit.GetByIdAsync(id);

                retval = _mapper.Map<TimeSheetRecordDto>(timeSheetRecord);
            }

            return retval;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "BASIC_ACCESS")]
        public async Task CreateTimeSheetRecordAsync(TimeSheetRecordDto timeSheetRecordDto)
        {
            using (var timeSheetRecordUnit = new UnitOfWork<TimeSheetRecord>(new ISDbContext()))
            {
                var timeSheetRecord = _mapper.Map<TimeSheetRecord>(timeSheetRecordDto);
                timeSheetRecord.Project = null;
                timeSheetRecord.Employee = null;

                await timeSheetRecordUnit.CreateAsync(timeSheetRecord);
            }
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "BASIC_ACCESS")]
        public async Task UpdateTimeSheetRecordAsync(TimeSheetRecordDto timeSheetRecordDto)
        {
            using (var timeSheetRecordUnit = new UnitOfWork<TimeSheetRecord>(new ISDbContext()))
            {
                var timeSheetRecord = _mapper.Map<TimeSheetRecord>(timeSheetRecordDto);
                timeSheetRecord.Employee = null;
                timeSheetRecord.Project = null;
                await timeSheetRecordUnit.UpdateAsync(timeSheetRecord);
            }
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "BASIC_ACCESS")]
        public async Task DeleteTimeSheetRecordAsync(int id)
        {
            using (var timeSheetRecordUnit = new UnitOfWork<TimeSheetRecord>(new ISDbContext()))
            {
                await timeSheetRecordUnit.DeleteAsync(id);
            }
        }

        private FilterDto BuildAttendanceFilter(int employeeId, int year, int month)
        {

            DateTime from = new DateTime(year, month, 1);
            var lastDayOfMonth = from.AddMonths(1).AddDays(-1);
            DateTime to = new DateTime(year, month, lastDayOfMonth.Day, 23, 59, 59);

            var filter = new FilterDto()
            {
                Conditions = new List<ConditionItemDto>()
                 {
                      new ConditionItemDto()
                      {
                           Column = nameof(AttendanceRecord.EmployeeId),
                           Type = ConditionTypeEnum.Equal,
                           Value = employeeId.ToString()
                      },
                      new ConditionItemDto()
                      {
                           Column = nameof(AttendanceRecord.TimeStamp),
                           Type = ConditionTypeEnum.GreaterOrEqual,
                           Value = from.ToString("yyyy-MM-dd HH:mm:ss.fff")
                      },
                      new ConditionItemDto()
                      {
                           Column = nameof(AttendanceRecord.TimeStamp),
                           Type = ConditionTypeEnum.LessOrEqual,
                           Value = to.ToString("yyyy-MM-dd HH:mm:ss.fff")
                      }
                 },
                Sorting = new List<SortingItemDto>()
                 {
                      new SortingItemDto()
                      {
                           Ascending = false,
                           Column = nameof(AttendanceRecord.TimeStamp),
                      }
                 }
            };

            return filter;
        }

        private FilterDto BuildTimeSheetFilter(int employeeId, int year, int month)
        {

            DateTime from = new DateTime(year, month, 1);
            var lastDayOfMonth = from.AddMonths(1).AddDays(-1);
            DateTime to = new DateTime(year, month, lastDayOfMonth.Day, 23, 59, 59);

            var filter = new FilterDto()
            {
                Conditions = new List<ConditionItemDto>()
                 {
                      new ConditionItemDto()
                      {
                           Column = nameof(TimeSheetRecord.EmployeeId),
                           Type = ConditionTypeEnum.Equal,
                           Value = employeeId.ToString()
                      },
                      new ConditionItemDto()
                      {
                           Column = nameof(TimeSheetRecord.From),
                           Type = ConditionTypeEnum.GreaterOrEqual,
                           Value = from.ToString("yyyy-MM-dd HH:mm:ss.fff")
                      },
                      new ConditionItemDto()
                      {
                           Column = nameof(TimeSheetRecord.To),
                           Type = ConditionTypeEnum.LessOrEqual,
                           Value = to.ToString("yyyy-MM-dd HH:mm:ss.fff")
                      }
                 },
                Sorting = new List<SortingItemDto>()
                 {
                      new SortingItemDto()
                      {
                           Ascending = false,
                           Column = nameof(TimeSheetRecord.From),
                      }
                 }
            };

            return filter;
        }

    }
}
