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.Scan.ScanMachineAvailability;
    using Hims.Shared.UserModels.ProviderLeave;

    /// <inheritdoc />
    [Authorize]
    [Route("api/scan-machine-availability")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class ScanMachineAvailabilityController : BaseController
    {
        /// <summary>
        /// The scam machine availability services.
        /// </summary>
        private readonly IScanMachineAvailabilityService scanMachineAvailabilityService;

        /// <summary>
        /// The scan service.
        /// </summary>
        private readonly IScanLogService scanLogService;

        /// <inheritdoc />
        public ScanMachineAvailabilityController(
           IScanMachineAvailabilityService scanMachineAvailabilityService,
            IScanLogService scanLogService)
        {
            this.scanMachineAvailabilityService = scanMachineAvailabilityService;
            this.scanLogService = scanLogService;
        }

        /// <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-machine-availability")] ///from wher it is hitting?
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ModifyAsync([FromBody] ScanMachineAvailabilityInsertModel request, [FromHeader] LocationHeader location)
        {
            request = (ScanMachineAvailabilityInsertModel)EmptyFilter.Handler(request);

            //request.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
            var response = request.ScanMachineAvailabilityId == 0
                               ? await this.scanMachineAvailabilityService.InsertAsync(request)
                               : await this.scanMachineAvailabilityService.UpdateAsync(request);

            switch (response)
            {
                case -1:
                    return this.Conflict("Given availability has already been exists with us.");
                case 0:
                    return this.ServerError();
                case -2:
                    return this.Conflict("Type Case Error");

                default:

                    if (response > 0)
                    {
                        var scanLogModel = new ScanLogModel
                        {
                            AccountId = request.ModifiedBy,
                            ScanLogTypeId = (int)ScanLogTypes.ScanMachineAvailability,
                            LogFrom = (short)request.LoginRoleId,
                            LogDate = DateTime.UtcNow.AddMinutes(330),
                            LocationId = Convert.ToInt32(request.LocationId),
                            LogDescription = request.ScanMachineAvailabilityId == 0 ? $"<b>{request.CreatedByName}</b> has Added Scan Machine Availability for the Machine : <b>{request.MachineName}</b>. " : $"<b>{request.CreatedByName}</b> has modified the Available days and Slots for Machine : <b>{request.MachineName}</b>.",
                        };
                        await this.scanLogService.LogAsync(scanLogModel);
                    }

                    return this.Success($"Aavailability has been {(request.ScanMachineAvailabilityId == 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] ScanMachineAvailabilityFilterModel model, [FromHeader] LocationHeader header)
        {
            model = (ScanMachineAvailabilityFilterModel)EmptyFilter.Handler(model);
            //model.LocationId = (int)(!string.IsNullOrEmpty(header.LocationId) ? int.Parse(header.LocationId) : (int?)null);
            var response = await this.scanMachineAvailabilityService.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] ScanMachineAvailabilityFetchModel model)
        {
            var response = await this.scanMachineAvailabilityService.FetchAltAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches selected machine availabilities.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-machine-availability")]
        [ProducesResponseType(typeof(List<ProviderLocationModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchSelectedMachineAvailabilityAsync([FromBody] ScanMachineAvailabilityFetchModel model)
        {
            var response = await this.scanMachineAvailabilityService.FetchMachineAvailabilityAsync(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(ScanMachineAvailabilityFilterModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                model = (ScanMachineAvailabilityFilterModel)EmptyFilter.Handler(model);
                var response = await this.scanMachineAvailabilityService.DeleteAsync(model.ScanMachineAvailabilityId);

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

                if (response > 0)
                {
                    var scanLogModel = new ScanLogModel
                    {
                        AccountId = model.ModifiedBy,
                        ScanLogTypeId = (int)ScanLogTypes.ScanMachineAvailability,
                        LogFrom = (short)model.RoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LocationId = Convert.ToInt32(header.LocationId),
                        LogDescription = $"<b>{model.CreatedByName}</b> has Deleted Scan Machine Availability for Machine : <b>{model.MachineName}</b>.",
                    };
                    await this.scanLogService.LogAsync(scanLogModel);
                }

                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>
        /// Fetches selected machine availability slots.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-machine-availability-for-multipleDays")]
        [ProducesResponseType(typeof(List<ProviderLocationModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchSelectedMachineAvailabilityBasedOnDaysAsync([FromBody] ScanMachineAvailabilityBasedOnDaysModel model)
        {
            var response = await this.scanMachineAvailabilityService.FetchMachineAvailabilityBasedOnDaysAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// The delete charge type.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - charge type deleted successfully.
        /// - 409 - charge type can not be deleted.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("cancel-scan-machine-availability")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> CancelAvailabilityAsync([FromBody] CancelModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                model = (CancelModel)EmptyFilter.Handler(model);
                //model.LocationId = Convert.ToInt32(header.LocationId);
                var availableDate = await this.scanMachineAvailabilityService.FindDateByScanAvailabilityId(model.ScanMachineAvailabilityId);
                var response = await this.scanMachineAvailabilityService.CancelAvailabilityAsync(model.ScanMachineAvailabilityId, model.FromDate, model.ToDate);
                if (response == 0)
                {
                    return this.ServerError();
                }
                if (response == -2)
                {
                    return this.Conflict("error in type casting");
                }
                var scanLogModel = new ScanLogModel
                {
                    AccountId = model.ModifiedBy,
                    ScanLogTypeId = (int)ScanLogTypes.ScanMachineAvailability,
                    LogFrom = (int)AccountType.Administrator,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LocationId = model.LocationId,
                    LogDescription = $" {model.ModifiedByName} has Cancelled Available Date - {availableDate} on {DateTime.UtcNow.AddMinutes(330)}",
                };
                await this.scanLogService.LogAsync(scanLogModel);
                return this.Success("Availability has been Cancelled successfully.");
            }
            catch (NpgsqlException exception)
            {
                if (exception.Message.Contains("violates foreign key constraint"))
                {
                    return this.Conflict("Availability cant be cancelled. Please contact Administrator.");
                }
                return this.ServerError();
            }
        }

    }
}
