namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using AutoMapper;
    using Domain.Services;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Models.Provider;
    using Newtonsoft.Json;
    using Npgsql;
    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.UserModels;
    using Shared.UserModels.Filters;
    using Utilities;

    using Hims.Domain.Helpers;
    using Hims.Shared.Library.Enums;
    using Hims.Shared.UserModels.Common;
    using Hims.Api.Models;
    using Hims.Shared.UserModels;

    /// <inheritdoc />
    [Authorize]
    [Route("api/ot-Room-availability")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class OTRoomAvailabilityController : BaseController
    {
        /// <summary>
        /// The scam machine availability services.
        /// </summary>
        private readonly IOTRoomAvailabilityService otRoomAvailabilityService;

        /// <summary>
        /// The AES helper.
        /// </summary>
        private readonly IAESHelper aesHelper;

        /// <summary>
        /// The mapper.
        /// </summary>
        private readonly IMapper mapper;

        /// <summary>
        /// The auditlog services.
        /// </summary>
        private readonly IAuditLogService auditLogServices;
        /// <summary>
        /// The coupon services.
        /// </summary>
        private readonly IRoomService roomService;

        /// <inheritdoc />
        public OTRoomAvailabilityController(
           IOTRoomAvailabilityService otRoomAvailabilityService,
            IAESHelper aesHelper, IRoomService roomService,

            IMapper mapper, IAuditLogService auditLogServices)
        {
            this.otRoomAvailabilityService = otRoomAvailabilityService;

            this.aesHelper = aesHelper;
            this.mapper = mapper;
            this.auditLogServices = auditLogServices;
            this.roomService = roomService;
        }

        /// <summary>
        /// The add scan availability.
        /// </summary>
        /// <param name="request">
        /// The request.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - scan location added successfully.
        /// - 409 - scan location already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("modify-ot-Room-availability")] ///from wher it is hitting?
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ModifyAsync([FromBody] OTRoomAvailabilityInsertModel request, [FromHeader] LocationHeader location)
        {
            request = (OTRoomAvailabilityInsertModel)EmptyFilter.Handler(request);
            request.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
            var response = request.OTRoomAvailabilityId == 0
                               ? await this.otRoomAvailabilityService.InsertAsync(request)
                               : await this.otRoomAvailabilityService.UpdateAsync(request);
            var roomName = await this.roomService.FetchRoomNameAsync(request.OTRoomId);
            switch (response)
            {
                case -1:
                    return this.Conflict("Given availability has already been exists with us.");
                case 0:
                    return this.ServerError();
                default:

                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = request.ModifiedBy,
                        LogTypeId = (int)LogTypes.OTAvailability,
                        LogFrom = (short)request.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = request.OTRoomAvailabilityId == 0 ? $"<b>{request.CreatedByName}</b> has added OT Availability for the OTRoom <b>{roomName}</b>  on { DateTime.UtcNow.AddMinutes(330) } . " : $"<b>{request.CreatedByName}</b> has modified the Available days and Slots for OT Room <b>{roomName}</b>  on { DateTime.UtcNow.AddMinutes(330) } .",
                        LocationId = Convert.ToInt32(request.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);


                    return this.Success($"OTRoom availability has been {(request.OTRoomAvailabilityId == 0 ? "added" : "updated")} successfully.");
            }
        }

        /// <summary>
        /// fetchmachineavailability.
        /// </summary>
        /// <param name="model"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-all")]
        [ProducesResponseType(typeof(List<ProviderLocationModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchMachineAvailabilityAsync([FromBody] OTRoomAvailabilityFilterModel model, [FromHeader] LocationHeader header)
        {
            model = (OTRoomAvailabilityFilterModel)EmptyFilter.Handler(model);
            model.LocationId = (int)(!string.IsNullOrEmpty(header.LocationId) ? int.Parse(header.LocationId) : (int?)null);
            var response = await this.otRoomAvailabilityService.FetchAllAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch")]
        [ProducesResponseType(typeof(List<ProviderLocationModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchMachineAvailabilityAsync([FromBody] OTRoomAvailabilityFetchModel model)
        {
            //model = (ScanMachineAvailabilityFetchModel)EmptyFilter.Handler(model);
            var response = await this.otRoomAvailabilityService.FetchAltAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// The delete provider location.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - ScanMachineAvailability deleted successfully.
        /// - 409 - ScanMachineAvailability can not be deleted.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpDelete]
        [Route("delete")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> DeleteAsync(OTRoomAvailabilityFilterModel model,[FromHeader] LocationHeader header)
        {
            try
            {
                model = (OTRoomAvailabilityFilterModel)EmptyFilter.Handler(model);
                var response = await this.otRoomAvailabilityService.DeleteAsync(model.OTRoomAvailabilityId);

                if (response == 0)
                {
                    return this.ServerError();
                }

                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.ModifiedBy,
                    LogTypeId = (int)LogTypes.Department,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = $"<b>{model.CreatedByName}</b> has Deleted Scan Machine Availability for Machine : <b>{model.RoomName}</b>.",
                    LocationId = Convert.ToInt32(header.LocationId)
                };
                await this.auditLogServices.LogAsync(auditLogModel);


                return this.Success("Your availability has been deleted successfully.");
            }
            catch (NpgsqlException exception)
            {
                if (exception.Message.Contains("violates foreign key constraint"))
                {
                    return this.Conflict("Provider location can't be deleted. Please contact administrator.");
                }

                return this.ServerError();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-specific")]
        [ProducesResponseType(typeof(List<ProviderLocationModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchFilterMachineAvailabilityAsync([FromBody] OTRoomAvailabilityFetchModel model)
        {            
            var response = await this.otRoomAvailabilityService.FetchFilterMachineAvailabilityAsync(model);
            return this.Success(response);
        }
        /// <summary>
        /// The fetch slots.
        /// </summary>
        /// <param name="model">
        /// The providerLocation filter model.
        /// </param>
        /// <returns>
        /// The list of TimeSlotModel.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// The following codes are returned
        /// - 200 - List of TimeSlotModel.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("fetch-slots-for-multipledays")]
        public async Task<ActionResult> FetchSlotsForMultipleDaysAsync([FromBody] Shared.UserModels.Slots.SlotRequest model)
        {
            var data = await this.otRoomAvailabilityService.FetchSlotsForMultipleDays(model);
            return this.Ok(new GenericResponse
            {
                Status = GenericStatus.Success,
                Data = data,
            });
        }
    }
}
