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

namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
{
	/// <summary>
	/// 
	/// </summary>
	/// <remarks>
	/// 
	/// </remarks>
	/// <param name="service"></param>
	/// <param name="cache"></param>
	/// <param name="logger"></param>
	[Authorize]
	[ApiController]
	[ApiVersion("1.0")]
	[ValidateAntiForgeryToken]
	[Route("api/v{version:apiVersion}/thisSystems")]

	public class ThisSystemController(IThisSystemService service, IEaseCache cache, ILogger<ThisSystemController> logger) : ControllerBase
	{
		private readonly ILogger _logger = logger;
		private readonly IEaseCache _cache = cache;
		private readonly IThisSystemService _service = service;
		private readonly DateTimeOffset _options = Helper.CreateEaseCacheOptions();

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

			BooleanResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			if (HttpContext.IsSessionExpired())
			{
				response.ReturnStatus = StatusCodes.Status401Unauthorized;
				response.ReturnMessage.Add("Session expired, Please Login again...");
				return StatusCode(StatusCodes.Status401Unauthorized, response);
			}

			bool permitted = await HttpContext.IsPermitted(moduleId: "ELIT.1.1_2");
			if (!permitted)
			{
				response.ReturnStatus = StatusCodes.Status403Forbidden;
				response.ReturnMessage.Add("You are not authorize to Update System Information.");
				return StatusCode(StatusCodes.Status417ExpectationFailed, response);
			}

			if (request.PwdMinLen > request.PwdMaxLen)
			{
				response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
				response.ReturnMessage.Add("Maximum length of password can not be less Minimum length of password");
				return StatusCode(StatusCodes.Status417ExpectationFailed, response);
			}

			if (request.EnfStgPwd && request.PwdMinLen < 6)
			{
				response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
				response.ReturnMessage.Add("For Strong Password minimum length of password can not be less 6");
				return StatusCode(StatusCodes.Status417ExpectationFailed, response);
			}

			string[] tokens = request.AutoLogoutParams.Split(',');
			if (tokens.Length != 3)
			{
				response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
				response.ReturnMessage.Add("Must be comma delimited 3 parameters (Idle, timeout and ping) in seconds.");
				return StatusCode(StatusCodes.Status417ExpectationFailed, response);
			}

			if (tokens.Length == 3)
			{
				if (!int.TryParse(tokens[0], out int tmValue))
				{
					response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
					response.ReturnMessage.Add("Idle parameter must be numeric (between 0 to 9999).");
					return StatusCode(StatusCodes.Status417ExpectationFailed, response);
				}
				if (tmValue < 0 || tmValue > 9999)
				{
					response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
					response.ReturnMessage.Add($"Idle [{tmValue}] parameter must be between 0 to 9999.");
					return StatusCode(StatusCodes.Status417ExpectationFailed, response);
				}

				if (!int.TryParse(tokens[1], out tmValue))
				{
					response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
					response.ReturnMessage.Add("Timeout parameter must be numeric (between 0 to 9999).");
					return StatusCode(StatusCodes.Status417ExpectationFailed, response);
				}
				if (tmValue < 0 || tmValue > 9999)
				{
					response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
					response.ReturnMessage.Add($"Timeout [{tmValue}] parameter must be between 0 to 9999.");
					return StatusCode(StatusCodes.Status417ExpectationFailed, response);
				}

				if (!int.TryParse(tokens[2], out tmValue))
				{
					response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
					response.ReturnMessage.Add("Ping parameter must be numeric (between 0 to 9999).");
					return StatusCode(StatusCodes.Status417ExpectationFailed, response);
				}
				if (tmValue < 0 || tmValue > 9999)
				{
					response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
					response.ReturnMessage.Add($"Ping [{tmValue}] parameter must be between 0 to 9999.");
					return StatusCode(StatusCodes.Status417ExpectationFailed, response);
				}
			}

			try
			{
				string ipAddress = Request.HttpContext.GetIpAddress();
				int userId = HttpContext.User.GetClaimValue<int>(Constants.UserId);
				response.Value = await _service.SaveAsync(request: request, ipAddress: ipAddress, modifiedBy: userId);
				response.ReturnMessage.Add("System Information saved successfully...");

				//Cache
				_cache.Clear("ThisSystem");

				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>
		/// <returns></returns>
		[ValidateSession]
		[HttpPost("getThisSystem")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ThisSystemResponse))]
		[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(ThisSystemResponse))]
		public async Task<IActionResult> GetThisSystem([FromBody] NoContentRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			ThisSystemResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			try
			{
				string key = "ThisSystem";
				string key2 = string.Empty;
				if (!_cache.TryGetValue(key: key, key2: key2, value: out response))
				{
					response = await _service.GetAsync();
					response.ReturnStatus = StatusCodes.Status200OK;

					//Cache
					_ = _cache.Set(key: key, key2: key2, value: response, options: _options);
				}

				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("saveStandardTerms")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BooleanResponse))]
		public async Task<IActionResult> SaveStandardTerms([FromBody] WOTermsRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			BooleanResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			bool permitted = await HttpContext.IsPermitted("ELIT.5.1.3_1") || await HttpContext.IsPermitted("ELIT.5.1.3_2");
			if (!permitted)
			{
				response.ReturnStatus = StatusCodes.Status403Forbidden;
				response.ReturnMessage.Add("You are not authorize to Save Work Order terms & conditions.");
				return StatusCode(StatusCodes.Status417ExpectationFailed, response);
			}

			try
			{
				string ipAddress = Request.HttpContext.GetIpAddress();
				int savedBy = HttpContext.User.GetClaimValue<int>(Constants.UserId);
				response.Value = await _service.SaveWOTermsAsync(request: request, ipAddress: ipAddress, savedBy: savedBy);
				response.ReturnMessage.Add("Work Order terms & conditions saved successfully...");

				//Cache
				_cache.Clear("WOTerms");

				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>
		/// <returns></returns>
		[ValidateSession]
		[HttpPost("getStandardTerms")]
		[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WOTermsResponse))]
		[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(WOTermsResponse))]
		public async Task<IActionResult> GetStandardTerms([FromBody] NoContentRequest request)
		{
			ArgumentNullException.ThrowIfNull(request);

			WOTermsResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
			try
			{
				string key = "WOTerms";
				string key2 = string.Empty;
				if (!_cache.TryGetValue(key: key, key2: key2, value: out response))
				{
					response = await _service.GetWOTermsAsync();
					response.ReturnStatus = StatusCodes.Status200OK;

					//Cache
					_ = _cache.Set(key: key, key2: key2, value: response, options: _options);
				}

				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);
			}
		}
	}
}
