using Asp.Versioning;
using OnlineSalesAutoCrop.CoreAPI.Configurations;
using OnlineSalesAutoCrop.CoreAPI.Models;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Setups;
using OnlineSalesAutoCrop.CoreAPI.Models.Responses;
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Setups;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Setups;
using OnlineSalesAutoCrop.CoreAPI.SignalRHub;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
{
	/// <summary>
	/// 
	/// </summary>                              
	[Authorize]
	[ApiController]
	[ApiVersion("1.0")]
	[ValidateAntiForgeryToken]
	[Route("api/v{version:apiVersion}/authModules")]
	public class AuthModulesController(IAuthModulesService service, IEaseCache cache, ILogger<AuthModulesController> logger, IHubContext<NotificationHub, INotificationHub> hub) : ControllerBase
	{
		private readonly ILogger _logger = logger;
		private readonly IEaseCache _cache = cache;
		private readonly IAuthModulesService _service = service;
		private readonly IHubContext<NotificationHub, INotificationHub> _hub = hub;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		[ValidateSession]
		[HttpPost("getAuthSummaries")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthSummariesResponse))]
		[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(AuthSummariesResponse))]
		public async Task<IActionResult> GetAuthSummaries([FromBody] AuthSummaryRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			AuthSummariesResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			try
			{
				int userId = HttpContext.User.GetClaimValue<int>(Constants.UserId);
				response = await _service.GetAuthSummariesAsync(userId: userId, status: request.Status, entryModule: 0);
				response.ReturnStatus = StatusCodes.Status200OK;

				return Ok(response);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex);
				response.ReturnStatus = StatusCodes.Status500InternalServerError;
				response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
				return StatusCode(StatusCodes.Status500InternalServerError, response);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		[ValidateSession]
		[HttpPost("getAuthDetails")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthDetailsResponse))]
		[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(AuthDetailsResponse))]
		public async Task<IActionResult> GetAuthDetails([FromBody] AuthDetailRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			AuthDetailsResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			try
			{
				response = await _service.GetAuthDetailsAsync(moduleId: request.ModuleId, status: request.Status);
				response.ReturnStatus = StatusCodes.Status200OK;

				return Ok(response);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex);
				response.ReturnStatus = StatusCodes.Status500InternalServerError;
				response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
				return StatusCode(StatusCodes.Status500InternalServerError, response);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		[ValidateSession]
		[HttpPost("updateAuthStatus")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BooleanResponse))]
		[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(BooleanResponse))]
		public async Task<IActionResult> UpdateAuthStatus([FromBody] AuthUpdateRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			BooleanResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			string key = GetPermissionKey(status: request.Status, description: out string description);
			bool permitted = await HttpContext.IsPermitted(key);
			if (!permitted)
			{
				response.ReturnStatus = StatusCodes.Status403Forbidden;
				response.ReturnMessage.Add($"You are not authorize to do {description}.");
				return StatusCode(StatusCodes.Status417ExpectationFailed, response);
			}

			try
			{
				string ids = string.Join(',', request.Ids);
				int userId = HttpContext.User.GetClaimValue<int>(Constants.UserId);
				string ipAddress = Request.HttpContext.GetIpAddress();
				string loginId = HttpContext.User.GetClaimValue<string>(Constants.LoginId);
				response.Value = await _service.UpdateAuthStatusAsync(moduleId: request.ModuleId, ipAddress: ipAddress, remarks: request.Remarks, status: request.Status, userId: userId, loginId: loginId, ids: ids);
				response.ReturnStatus = StatusCodes.Status200OK;

				#region Clear Cache
				switch (request.ModuleId)
				{
					case "ELIT.3.1.1":
					case "ELIT.3.1.2":
						_cache.Clear("ChartofAccount");
						break;

					case "ELIT.1.5.1":
					case "ELIT.1.5.2":
						_cache.Clear("Client");
						break;

					case "ELIT.1.5.8":
						_cache.Clear("BankBranch");
						break;

					case "ELIT.1.5.9":
					case "ELIT.4.1.1":
					case "ELIT.4.1.2":
					case "ELIT.4.1.3":
					case "ELIT.5.1.6":
					case "ELIT.1.5.10":
					case "ELIT.6.1.6":
						_cache.Clear("GlCode");
						break;

					case "ELIT.1.5.3":
					case "ELIT.1.5.4":
					case "ELIT.1.5.5":
						_cache.Clear("Employee");
						break;

					case "ELIT.1.5.7":
					case "ELIT.6.1.5":
						_cache.Clear("Store");
						break;

					case "ELIT.6.1.4":
						_cache.Clear("Location");
						break;

					case "ELIT.5.1.1":
						_cache.Clear("ProductTypes");
						break;

					case "ELIT.5.1.2":
						_cache.Clear("Products");
						break;

					case "ELIT.6.1.1":
						_cache.Clear("AssetType");
						break;

					case "ELIT.6.1.2":
						_cache.Clear("AssetCategory");
						break;

					case "ELIT.6.1.3":
						_cache.Clear("AssetItem");
						break;

					case "ELIT.7.1.3":
						_cache.Clear("Priority");
						break;

					case "ELIT.7.1.4":
						_cache.Clear("TaskStatus");
						break;

					case "ELIT.7.1.5":
						_cache.Clear("TaskCategory");
						break;

					case "ELIT.7.1.6":
						_cache.Clear("TaskType");
						break;

					case "ELIT.7.1.7":
						_cache.Clear("TeamSpace");
						break;

					case "ELIT.9.1.1":
						_cache.Clear("MarketHierarchy");
						break;

					case "ELIT.9.1.2":
						_cache.Clear("Salespoint");
						break;

					case "ELIT.9.1.3":
						_cache.Clear("ProductHierarchy");
						break;

					case "ELIT.9.1.4":
						_cache.Clear("Brand");
						break;

					case "ELIT.9.1.5":
						_cache.Clear("Sku");
						break;

					case "ELIT.9.1.6":
						_cache.Clear("ChannelHierarchy");
						break;

					case "ELIT.9.1.7":
						_cache.Clear("Customer");
						break;

					case "ELIT.9.1.8":
						_cache.Clear("SalesOfficer");
						break;

					case "ELIT.9.1.12":
						_cache.Clear("ExtnlProduct");
						break;

					case "ELIT.9.1.13":
						_cache.Clear("SalesPromotion");
						break;

					default:
						break;
				}
				#endregion

				if (request.Status == 8)
				{
					await _hub.Clients.All.NotifySubscriber(userId: userId, msgType: 5, itemId: 0, ipAddress: ipAddress);
				}
				return Ok(response);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex);
				response.ReturnStatus = StatusCodes.Status500InternalServerError;
				response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
				return StatusCode(StatusCodes.Status500InternalServerError, response);
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		[ValidateSession]
		[HttpPost("getPendingAuths")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PendingAuthResponse))]
		[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(PendingAuthResponse))]
		public async Task<IActionResult> GetPendingAuths([FromBody] NoContentRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			PendingAuthResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			try
			{
				int userId = HttpContext.User.GetClaimValue<int>(Constants.UserId);
				response = await _service.GetPendingAuthsAsync(userId: userId);
				response.ReturnStatus = StatusCodes.Status200OK;

				return Ok(response);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex);
				response.ReturnStatus = StatusCodes.Status500InternalServerError;
				response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
				return StatusCode(StatusCodes.Status500InternalServerError, response);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="status"></param>
		/// <param name="description"></param>
		/// <returns></returns>
		private static string GetPermissionKey(short status, out string description)
		{
			string permissionKey;
			switch (status)
			{
				case 16:
					permissionKey = "ELIT.2.3_2";
					description = "Deactivation";
					break;

				case 8:
					permissionKey = "ELIT.2.2_2";
					description = "Authorization";
					break;

				default:
					permissionKey = "ELIT.2.1_2";
					description = "Authentication";
					break;
			}

			return permissionKey;
		}
	}
}