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;
    using Hims.Shared.UserModels.OperationTheater;

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

        /// <summary>
        /// The AES helper.
        /// </summary>
        private readonly IAESHelper aesHelper;
        /// <summary>
        /// The coupon services.
        /// </summary>
        private readonly IRoomService roomService;
        /// <summary>
        /// The mapper.
        /// </summary>
        private readonly IMapper mapper;
        /// <summary>
        /// The patient services.
        /// </summary>
        private readonly IPatientService patientService;

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

        /// <inheritdoc />
        public OTRegisterController(
           IOTRegisterService otRoomRegisterService,
            IAESHelper aesHelper,
            IPatientService patientService,
            IMapper mapper, IAuditLogService auditLogServices,
            IRoomService roomService)
        {
            this.otRoomRegisterService = otRoomRegisterService;
            this.patientService = patientService;
            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-Register")] ///from wher it is hitting?
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ModifyAsync([FromBody] OTRegisterInsertModel request, [FromHeader] LocationHeader location)
        {
            request = (OTRegisterInsertModel)EmptyFilter.Handler(request);
            var response = request.OTRegisterId == 0
                               ? await this.otRoomRegisterService.InsertAsync(request)
                               : await this.otRoomRegisterService.UpdateAsync(request);
            var patientName = await this.patientService.FindAsync(request.PatientId);
            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.CreatedBy,
                        LogTypeId = (int)LogTypes.OTAppointment,
                        LogFrom = (int)AccountType.Administrator,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = request.OTRegisterId == 0 ? $"<b>{request.CreatedByName}</b> has added OT appointment for Patient <b>{patientName.FullName} in OTRoom  {roomName} on { DateTime.UtcNow.AddMinutes(330) } Successfully. " : $"<b>{request.CreatedByName}</b> has modified the Available days and Slots for OTRoom on { DateTime.UtcNow.AddMinutes(330) }.",
                        LocationId = Convert.ToInt32(request.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                    //return this.Success($"Your availability has been {(request.OTRegisterId == 0 ? "added" : "updated")} successfully.");
                    return this.Success(response);
            }
        }

        [HttpPut]
        [Authorize]
        [Route("reschedule")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> RescheduleAsync([FromBody] RescheduleOTAppointmentRequest model, [FromHeader] LocationHeader header)
        {
            model = (RescheduleOTAppointmentRequest)EmptyFilter.Handler(model);
            model.LocationId = int.Parse(header.LocationId);
            var response = await this.otRoomRegisterService.RescheduleAsync(model.OTRegisterId, Convert.ToInt32(model.ModifiedBy), model.AppointmentDate, model.AppointmentEndTime, model.OTRoomId);
            var patientName = await this.patientService.FindAsync(model.PatientId);
            var roomName = await this.roomService.FetchRoomNameAsync(model.OTRoomId);
            var list = new List<string>();
           
                if (response == 0)
            {
                return this.ServerError();
            }
            var auditLogModel = new AuditLogModel
            {
                AccountId = model.ModifiedBy,
                LogTypeId = (int)LogTypes.OTAppointment,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.UtcNow,
                LocationId = model.LocationId,
                LogDescription = $@"{model.CreatedByName} has rescheduled OT Appointment for Patient : <b>{patientName.FullName} in OTRoom {roomName} on { DateTime.UtcNow.AddMinutes(330) } Successfully."

            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success(response);

        }

        [HttpPost]
        [Authorize]
        [Route("cancel")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> CancelAsync([FromBody] OTRegisterInsertModel model)
        {
            
            model = (OTRegisterInsertModel)EmptyFilter.Handler(model);
            var response = await this.otRoomRegisterService.CancelAsync(model);
            var patientName = await this.patientService.FindAsync(model.PatientId);
                var res = await this.otRoomRegisterService.FetchAltAsync(model.OTRegisterId);
            if (response == 0)
            {
                return this.ServerError();
            }
            if (response > 0)
            {
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.CreatedBy,
                    LogTypeId = (int)LogTypes.OTAppointment,
                    LogFrom = (short)model.LoginRoleId,
                    LogDate = DateTime.UtcNow,
                    LocationId = (int)model.LocationId,
                    LogDescription = $@"{model.CreatedByName} has Cancelled OT Appointment for Patient : <b>{patientName.FullName} in OTRoom {res} on { DateTime.UtcNow.AddMinutes(330) } Successfully."

                };
                await this.auditLogServices.LogAsync(auditLogModel);
            }
            return this.Success(response);
        }

        /// <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> FetchOTRoomAvailabilityAsync([FromBody] OTRegisterFilterModel model, [FromHeader] LocationHeader header)
        {
            model = (OTRegisterFilterModel)EmptyFilter.Handler(model);            
            var response = await this.otRoomRegisterService.FetchAllAsync(model);
            return this.Success(response);

        }
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch")]
        [ProducesResponseType(typeof(List<ProviderLocationModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchOTRoomAvailabilityAsync([FromBody] OTFilterModel request)
        {                       
            request = (OTFilterModel)EmptyFilter.Handler(request);           
                var filterResponse = await this.otRoomRegisterService.FetchFilterEvent(request);
                return this.Success(filterResponse);            
        }

        /// <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>
        [HttpPost]
        [Route("delete")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> DeleteAsync([FromBody] OTRegisterFilterModel model,[FromHeader] LocationHeader header)
        {
            try
            {
                model = (OTRegisterFilterModel)EmptyFilter.Handler(model);
                var response = await this.otRoomRegisterService.DeleteAsync(model.OTRegisterId);

                if (response == 0)
                {
                    return this.ServerError();
                }
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.CreatedBy,
                    LogTypeId = (int)LogTypes.OTAppointment,
                    LogFrom = (int)AccountType.Administrator,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = $"<b>{model.CreatedByName}</b> has Deleted operation from OTRegister: <b>{model.SurgeryId}</b>.",
                    LocationId = Convert.ToInt32(header.LocationId)
                };
                await this.auditLogServices.LogAsync(auditLogModel);


                return this.Success("Your record 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();
            }
        }
    }
}
