using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Schedulings;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.Schedulings;
using Hotline.Share.Dtos.Settings;
using Hotline.Share.Requests;
using Hotline.Tools;
using Hotline.Users;
using MapsterMapper;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System.Data;
using System.Dynamic;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Api.Controllers
{
    public class SchedulingController : BaseController
    {
        private readonly IRepository<Scheduling> _schedulingRepository;
        private readonly IRepository<SchedulingShift> _schedulingShiftRepository;
        private readonly IRepository<SchedulingUser> _schedulingUserRepository;
        private readonly IRepository<User> _userRepository;
        private readonly IMapper _mapper;

        public SchedulingController(
            IRepository<Scheduling> schedulingRepository,
            IRepository<SchedulingShift> schedulingShiftRepository,
            IRepository<SchedulingUser> schedulingUserRepository,
            IRepository<User> userRepository,
            IMapper mapper
            )
        {
            _schedulingRepository = schedulingRepository;
            _schedulingShiftRepository = schedulingShiftRepository;
            _schedulingUserRepository = schedulingUserRepository;
            _mapper = mapper;
            _userRepository = userRepository;
        }
        #region 排班人员

        /// <summary>
        /// 新增排班人员
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost("user")]
        public async Task Add([FromBody] List<UserAddDto> dtos)
        {
            List<SchedulingUser> user = new List<SchedulingUser>();
            foreach (var dto in dtos)
            {
                if (string.IsNullOrEmpty(dto.UserId))
                    throw UserFriendlyException.SameMessage("请带上用户信息");
                var schedulingUser = await _schedulingUserRepository.Queryable().Where(x => x.UserId == dto.UserId).AnyAsync();
                if (!schedulingUser)
                {
                    var model = _mapper.Map<SchedulingUser>(dto);
                    var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
                    model.OrgId = sysUser.Organization.Id;
                    model.OrgIdName = sysUser.Organization.Name;
                    user.Add(model);
                }
            }

            if (user.Any())
                await _schedulingUserRepository.AddRangeAsync(user, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除排班人员
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpDelete("user")]
        public async Task Delete([FromBody] UserDeleteDto dto)
        {
            foreach (var Id in dto.Ids)
            {
                await _schedulingUserRepository.RemoveAsync(x => x.Id == Id);
            }
        }

        /// <summary>
        /// 更新排班人员
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("user")]
        public async Task Update([FromBody] UserUpdateDto dto)
        {
            var user = await _schedulingUserRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (user is null)
                throw UserFriendlyException.SameMessage("无效排班人员");
            _mapper.Map(dto, user);
            var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == dto.UserId).FirstAsync(HttpContext.RequestAborted);
            user.OrgId = sysUser.Organization.Id;
            user.OrgIdName = sysUser.Organization.Name;
            await _schedulingUserRepository.UpdateAsync(user, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 批量更新排班人员
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("batch_user")]
        public async Task Update([FromBody] List<UserUpdateDto> dto)
        {
            List<SchedulingUser> users = new List<SchedulingUser>();
            foreach (var item in dto)
            {
                var user = await _schedulingUserRepository.GetAsync(item.Id, HttpContext.RequestAborted);
                if (user is null)
                    throw UserFriendlyException.SameMessage("无效排班人员");
                _mapper.Map(dto, user);
                var sysUser = await _userRepository.Queryable().Includes(u => u.Organization).Where(x => x.Id == item.UserId).FirstAsync(HttpContext.RequestAborted);
                user.OrgId = sysUser.Organization.Id;
                user.OrgIdName = sysUser.Organization.Name;
                users.Add(user);
            }
            await _schedulingUserRepository.UpdateRangeAsync(users, HttpContext.RequestAborted);
        }


        /// <summary>
        /// 获取排班人员列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("user_list")]
        public async Task<PagedDto<SchedulingUser>> List([FromQuery] UserListDto dto)
        {
            var (total, items) = await _schedulingUserRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.UserName.Contains(dto.Keyword!))
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<SchedulingUser>(total, items);
        }

        /// <summary>
        /// 获取排班人员实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("user/{id}")]
        public async Task<SchedulingUser> UserEntity(string id)
        {
            return await _schedulingUserRepository.Queryable()
                .FirstAsync(x => x.Id == id);
        }

        #endregion

        #region 班次管理

        /// <summary>
        /// 新增班次管理
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost("shift")]
        public async Task Add([FromBody] ShiftAddDto dto)
        {
            var model = _mapper.Map<SchedulingShift>(dto);
            await _schedulingShiftRepository.AddAsync(model, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除班次管理
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpDelete("shift")]
        public async Task Delete([FromBody] ShiftDeleteDto dto)
        {
            foreach (var Id in dto.Ids)
            {
                await _schedulingShiftRepository.RemoveAsync(x => x.Id == Id);
            }
        }

        /// <summary>
        /// 更新班次管理
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("shift")]
        public async Task Update([FromBody] ShiftUpdateDto dto)
        {
            var shift = await _schedulingShiftRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (shift is null)
                throw UserFriendlyException.SameMessage("无效班次信息");
            _mapper.Map(dto, shift);
            await _schedulingShiftRepository.UpdateAsync(shift, HttpContext.RequestAborted);
        }


        /// <summary>
        /// 获取班次管理列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("shift_list")]
        public async Task<PagedDto<SchedulingShift>> List([FromQuery] ShiftListDto dto)
        {
            var (total, items) = await _schedulingShiftRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Name.Contains(dto.Keyword!))
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<SchedulingShift>(total, items);
        }

        /// <summary>
        /// 获取班次管理实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("shift/{id}")]
        public async Task<SchedulingShift> ShiftEntity(string id)
        {
            return await _schedulingShiftRepository.Queryable()
                .FirstAsync(x => x.Id == id);
        }
        #endregion

        #region 排班管理
        /// <summary>
        /// 新增排班管理
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task Add([FromBody] AddDto dtos)
        {
            List<Scheduling> schedulings = new List<Scheduling>();

            if (string.IsNullOrEmpty(dtos.ShiftId))
                throw UserFriendlyException.SameMessage("请传入排班班次信息");
            var shift = await _schedulingShiftRepository.GetAsync(dtos.ShiftId, HttpContext.RequestAborted);
            if (shift == null)
                throw UserFriendlyException.SameMessage("传入排班班次信息错误");
            foreach (var Id in dtos.UserIds)
            {
                if (string.IsNullOrEmpty(Id))
                    throw UserFriendlyException.SameMessage("请传入排班用户信息");
                var user = await _schedulingUserRepository.GetAsync(Id, HttpContext.RequestAborted);
                if (user == null)
                    throw UserFriendlyException.SameMessage("传入排班用户信息错误");

                if (dtos.SchedulingStartTime.HasValue && dtos.SchedulingEndTime.HasValue)
                {
                    for (int i = 0; dtos.SchedulingStartTime.Value.AddDays(i) <= dtos.SchedulingEndTime.Value; i++)
                    {
                        var schedulingTime = dtos.SchedulingStartTime.Value.AddDays(i);
                        var oldScheduling = await _schedulingRepository.Queryable().Where(x => x.SchedulingUserId == user.Id && x.ShiftId == dtos.ShiftId && x.SchedulingTime == schedulingTime).AnyAsync();
                        if (!oldScheduling)
                        {
                            var scheduling = new Scheduling
                            {
                                SchedulingUserId = user.Id,
                                SchedulingUserName = user.UserName,
                                ShiftId = dtos.ShiftId,
                                ShiftName = shift.Name,
                                SchedulingTime = schedulingTime,
                                WorkingTime = shift.WorkingTime,
                                OffDutyTime = shift.OffDutyTime,
                                SendOrderNum = 0
                            };
                            schedulings.Add(scheduling);
                        }
                    }
                }
                else
                {
                    var oldScheduling = await _schedulingRepository.Queryable().Where(x => x.SchedulingUserId == user.Id && x.ShiftId == dtos.ShiftId && x.SchedulingTime == dtos.SchedulingTime).AnyAsync();
                    if (!oldScheduling)
                    {
                        var scheduling = new Scheduling
                        {
                            SchedulingUserId = user.Id,
                            SchedulingUserName = user.UserName,
                            ShiftId = dtos.ShiftId,
                            ShiftName = shift.Name,
                            SchedulingTime = dtos.SchedulingTime,
                            WorkingTime = shift.WorkingTime,
                            OffDutyTime = shift.OffDutyTime,
                            SendOrderNum = 0
                        };
                        schedulings.Add(scheduling);
                    }
                }
            }
            await _schedulingRepository.AddRangeAsync(schedulings, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 删除排班管理
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpDelete]
        public async Task Delete([FromBody] DeleteDto dto)
        {
            foreach (var Id in dto.Ids)
            {
                await _schedulingRepository.RemoveAsync(x => x.Id == Id);
            }
        }

        /// <summary>
        /// 更新排班管理
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut]
        public async Task Update([FromBody] UpdateDto dto)
        {
            var scheduling = await _schedulingRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
            if (scheduling is null)
                throw UserFriendlyException.SameMessage("无效排班信息");
            var shift = await _schedulingShiftRepository.GetAsync(dto.ShiftId, HttpContext.RequestAborted);
            if (shift == null)
                throw UserFriendlyException.SameMessage("传入排班班次信息错误");
            _mapper.Map(dto, scheduling);
            scheduling.ShiftName = shift.Name;
            scheduling.WorkingTime = shift.WorkingTime;
            scheduling.OffDutyTime = shift.OffDutyTime;
            await _schedulingRepository.UpdateAsync(scheduling, HttpContext.RequestAborted);
        }

        ///// <summary>
        ///// 批量更新排班管理
        ///// </summary>
        ///// <param name="dto"></param>
        ///// <returns></returns>
        //[HttpPut("batch")]
        //public async Task Update([FromBody] List<UpdateDto> dto)
        //{
        //	List<Scheduling> schedulings = new List<Scheduling>();
        //	foreach (var item in dto)
        //	{
        //		var scheduling = await _schedulingRepository.GetAsync(item.Id, HttpContext.RequestAborted);
        //		if (scheduling is null)
        //			throw UserFriendlyException.SameMessage("无效排班信息");
        //		_mapper.Map(dto, scheduling);
        //		schedulings.Add(scheduling);
        //	}
        //	await _schedulingRepository.UpdateRangeAsync(schedulings, HttpContext.RequestAborted);
        //}


        /// <summary>
        /// 获取排班管理列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("list")]
        public async Task<PagedDto<Scheduling>> List([FromQuery] ListDto dto)
        {
            var (total, items) = await _schedulingRepository.Queryable()
                .Includes(x => x.SchedulingUser)
                .Includes(x => x.SchedulingShift)
                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.ShiftName.Contains(dto.Keyword!))
                .WhereIF(dto.StartTime.HasValue, x => x.SchedulingTime >= dto.StartTime)
                .WhereIF(dto.EndTime.HasValue, x => x.SchedulingTime <= dto.EndTime)
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<Scheduling>(total, items);
        }

        /// <summary>
        /// 排班数据查询
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("data")]
        public async Task<List<IDictionary<string, object>>> Data([FromQuery] DataDto dto)
        {
            List<IDictionary<string, object>> res = new List<IDictionary<string, object>>();
            var startTime = DateTime.Parse(dto.Time.ToString("yyyy-MM") + "-01");
            var endTime = startTime.AddMonths(1).AddDays(-1);
            DataTable data = await _schedulingRepository.Queryable().Where(x => x.SchedulingTime >= startTime && x.SchedulingTime <= endTime).ToDataTableAsync();
            if (data == null || data.Rows.Count <= 0) return res;
            var names = data.AsEnumerable().Select(x => new { SchedulingUserName = x.Field<string>("SchedulingUserName"), SchedulingUserId = x.Field<string>("SchedulingUserId") }).Distinct().OrderBy(x => x.SchedulingUserName).ToList();

            foreach (var item in names)
            {
                dynamic dynamicObj = new ExpandoObject();
                var dict = (IDictionary<string, object>)dynamicObj;
                var userName = "SchedulingUserName";
                dict[userName] = item.SchedulingUserName!;
                var scheduling = data.AsEnumerable().Where(x => x.Field<string>("SchedulingUserName") == item.SchedulingUserName).OrderBy(x => x.Field<DateTime>("SchedulingTime")).ToList();
                var userId = "UserId";
                dict[userId] = item.SchedulingUserId!;
                foreach (DataRow row in scheduling)
                {
                    var obj = new { Name = row.Field<string>("ShiftName"), Id = row.Field<string>("Id") };
                    var tiem = row.Field<DateTime>("SchedulingTime").ToString("yyyy-MM-dd");
                    dict[tiem] = obj;
                }
                res.Add(dict);
            }
            return res;
        }

        /// <summary>
        /// 获取排班管理实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<Scheduling> Entity(string id)
        {
            return await _schedulingRepository.Queryable()
                .FirstAsync(x => x.Id == id);
        }
        #endregion

        #region 值班管理列表
        /// <summary>
        /// 值班管理列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("get-scheduling-statistics-list")]
        public async Task<PagedDto<SchedulingStatisticsDto>> GetSchedulingStatisticsList([FromQuery] PagedKeywordRequest dto)
        {
            var (total, items) = await GetList(dto)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<SchedulingStatisticsDto>(total, items);
        }

        /// <summary>
        /// 值班管理列表导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("get-scheduling-statistics-list-export")]
        public async Task<FileStreamResult> GetSystemMobilAreaListExport([FromBody] ExportExcelDto<SystemMobilAreaRequestDto> dto)
        {
            var query = GetList(dto.QueryDto);
            List<SchedulingStatisticsDto> data;
            if (dto.IsExportAll)
            {
                data = await query.ToListAsync(HttpContext.RequestAborted);
            }
            else
            {
                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
                data = items;
            }

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<SchedulingStatisticsDto>(dto.ColumnInfos);

            var dtos = data
                .Select(stu => _mapper.Map(stu, typeof(SchedulingStatisticsDto), dynamicClass))
                .Cast<object>()
                .ToList();

            var stream = ExcelHelper.CreateStream(dtos);

            return ExcelStreamResult(stream, "值班管理列表");
        }

        private ISugarQueryable<SchedulingStatisticsDto> GetList(PagedKeywordRequest dto)
        {
            return _schedulingRepository.Queryable()
                     .Where(p => p.WorkingTime.ToString() != "00:00:00")
                    .WhereIF(dto.StartTime.HasValue, p => p.SchedulingTime >= dto.StartTime)
                    .WhereIF(dto.EndTime.HasValue, p => p.SchedulingTime <= dto.EndTime)
                    .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.SchedulingUserName == dto.Keyword)
                    .GroupBy(p => new { Date=p.SchedulingTime.Value.ToString("yyyy-MM"), p.SchedulingUserName })
                    .Select(p => new SchedulingStatisticsDto
                    {
                        Date = p.SchedulingTime.Value.ToString("yyyy-MM"),
                        UserName = p.SchedulingUserName,
                        Count = SqlFunc.AggregateCount(p.SchedulingUserName)
                    })
                    .OrderBy(p => p.Date);
        }
        #endregion
    }
}
