using Hims.Shared.UserModels.Common;

namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Domain.Helpers;
    using Hims.Shared.DataFilters;
    using Hims.Shared.EntityModels;
    using Hims.Shared.Library.Enums;
    using Hims.Shared.UserModels;
    using Hims.Shared.UserModels.NurseShift.BedView;
    using Hims.Shared.UserModels.NurseShift.Module;
    using Microsoft.AspNetCore.Mvc;
    using Utilities;

    /// <inheritdoc />
    [Route("api/nurse-module")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class NurseModuleController : BaseController
    {
        /// <summary>
        /// The auditlog services.
        /// </summary>
        private readonly IAuditLogService auditLogServices;

        /// <summary>
        /// The auditlog services.
        /// </summary>
        private readonly IAESHelper aeshelper;

        /// <summary>
        /// The nurse module services.
        /// </summary>
        private readonly INurseModuleService nurseModuleServices;

        /// <inheritdoc />
        public NurseModuleController(
            IAuditLogService auditLogServices,
            INurseModuleService nurseModuleServices,
            IAESHelper aeshelper)
        {

            this.auditLogServices = auditLogServices;
            this.nurseModuleServices = nurseModuleServices;
            this.aeshelper = aeshelper;
        }

        /// <summary>
        /// The fetch nurse.
        /// </summary>
        /// <returns>
        /// The list of nurse.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - List of Widgets.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("fetch")]
        public async Task<ActionResult> FetchNurseAsync([FromBody] NurseFilterModel model)
        {
            try
            {
                var records = await this.nurseModuleServices.FetchAsync(model).ConfigureAwait(false);
                foreach (var record in records)
                {
                    record.AccountEncryptId = this.aeshelper.Encrypt(record.AccountId.ToString());
                }
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = records
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// The fetch shift slots.
        /// </summary>
        /// <returns>
        /// The list of shift slots.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - List of Widgets.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpGet]
        [Route("fetch-shift-slots")]
        public async Task<ActionResult> FetchShiftSlotsAsync()
        {
            try
            {
                var shiftSlots = await this.nurseModuleServices.FetchSlotsAsync().ConfigureAwait(false);
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = shiftSlots
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// The insert slot async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-shift-slot")]
        public async Task<ActionResult> InsertAsync([FromBody] ShiftSlotModel model, [FromHeader] LocationHeader header)
        {
            model.StartTime = new TimeSpan(model.StartHour, model.StartMinute, 0);
            model.EndTime = new TimeSpan(model.EndHour, model.EndMinute, 0);
            var response = await this.nurseModuleServices.InsertSlotsAsync(model).ConfigureAwait(false);

            if (response > 0)
            {
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.CreatedBy,
                    LogTypeId = (int)LogTypes.ShiftSlot,
                    LogFrom = (short)model.LogFrom,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = $@"{model.CreatedByName} has added a new slot '{model.StartTime}-{model.EndTime}' on {DateTime.UtcNow.AddMinutes(330)}",
                    LocationId = Convert.ToInt32(header.LocationId)
                };
                await this.auditLogServices.LogAsync(auditLogModel);
            }

            return this.Success(response);

        }

        /// <summary>
        /// The insert widget async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-shift")]
        public async Task<ActionResult> InsertAsync([FromBody] ShiftModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                var response = await this.nurseModuleServices.InsertShiftAsync(model).ConfigureAwait(false);

                if (response.Status == GenericStatus.Success)
                {
                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = model.CreatedBy,
                        LogTypeId = (int)LogTypes.Shift,
                        LogFrom = (short)model.LogFrom,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"{model.CreatedByName} has added a new shift '{model.Name}' on {DateTime.UtcNow.AddMinutes(330)}",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }

                return Ok(response);
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// The update widget async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("update-shift")]
        public async Task<ActionResult> UpdateAsync([FromBody] ShiftModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                var response = await this.nurseModuleServices.UpdateShiftAsync(model).ConfigureAwait(false);

                if (response.Status == GenericStatus.Success)
                {
                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = model.ModifiedBy,
                        LogTypeId = (int)LogTypes.Shift,
                        LogFrom = (short)model.LogFrom,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"{model.ModifiedByName} has updated shift <br/>name: '{model.Name}' on {DateTime.UtcNow.AddMinutes(330)}",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }

                return Ok(response);
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// The update widget async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("modify-status")]
        public async Task<ActionResult> ModifyStatusAsync([FromBody] ShiftModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                //model = (ShiftModel)EmptyFilter.Handler(model);
                var response = await this.nurseModuleServices.ModifyStatusAsync(model).ConfigureAwait(false);
                if (response > 0)
                {
                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = model.ModifiedBy,
                        LogTypeId = (int)LogTypes.Shift,
                        LogFrom = (short)model.LogFrom,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = model.Active == true ? $@"{model.ModifiedByName} has Activated status of shift <br/>name: '{model.Name}' on {DateTime.UtcNow.AddMinutes(330)}" : $@"{model.ModifiedByName} has Deactivated status of shift <br/>name: '{model.Name}' on {DateTime.UtcNow.AddMinutes(330)}",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                return Ok(response);
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        [HttpPost]
        [Route("fetch-bed-wise")]
        public async Task<ActionResult> FetchBedWiseAsync([FromBody] BedViewFilterModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                var data = await this.nurseModuleServices.FetchBedWiseAsync(model).ConfigureAwait(false);
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = data,
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message,
                });
            }
        }

        [HttpPost]
        [Route("fetch-available-nurse")]
        public async Task<ActionResult> FetchBedWiseAsync([FromBody] AvailableNursePayloadModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                var data = await this.nurseModuleServices.GetAvailableNurseAsync(model).ConfigureAwait(false);
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = data,
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message,
                });
            }
        }

        [HttpPost]
        [Route("fetch-shifts-basics")]
        public async Task<ActionResult> FetchShiftsBasicsAsync( [FromHeader] LocationHeader header)
        {
            try
            {
                var data = await this.nurseModuleServices.FetchShiftsBasicsAsync().ConfigureAwait(false);
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = data,
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message,
                });
            }
        }

        /// <summary>
        /// The fetch shifts.
        /// </summary>
        /// <returns>
        /// The list of shifts.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - List of shifts.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("fetch-shifts")]
        public async Task<ActionResult> FetchShiftsAsync([FromBody] ShiftsFilterModel model)
        {
            try
            {
                var shifts = await this.nurseModuleServices.FetchShiftAsync(model).ConfigureAwait(false);

                var list = new List<ShiftsParentModel>();
                var uniqueShiftIds = shifts.ToList().Select(x => x.ShiftId).Distinct().ToArray();
                foreach (var shiftId in uniqueShiftIds)
                {
                    var obj = shifts.FirstOrDefault(x => x.ShiftId == shiftId);
                    var items = shifts.Where(x => x.ShiftId == shiftId && x.StartTime != null);
                    var subList = new ShiftsParentModel
                    {
                        Name = obj.Name,
                        ShiftId = obj.ShiftId,
                        Active = obj.Active,
                        Slots = items.Any() ? items.Select(x => new ShiftsChildModel
                        {
                            EndTime = x.EndTime ?? TimeSpan.Zero,
                            ShiftSlotId = x.ShiftSlotId,
                            StartTime = x.StartTime ?? TimeSpan.Zero
                        }).ToList() : new List<ShiftsChildModel>()
                    };
                    list.Add(subList);
                }

                if (list.Any())
                {
                    list = list.OrderByDescending(x => x.ShiftId).ToList();
                    list.ElementAt(0).TotalItems = shifts.ElementAt(0).TotalItems;
                }

                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = list
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }
    }
}