using IWS5.Api.OptionsSetup;
using IWS5.Core.DTO;
using IWS5.Core.Enums;
using IWS5.Core.Models.Request;
using IWS5.Core.Models.Request.Process;
using IWS5.Core.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace IWS5.Api.Controllers;

/// <summary>
/// Controller for managing processes.
/// </summary>
/// <param name="processService">Service for handling process-related operations.</param>
/// <param name="processDocumentTemplateRightsService"></param>
/// <param name="logger">Logger for logging information and errors.</param>
[Authorize]
[Route("api/[controller]")]
[ApiController]
[SwaggerTag("Controller for managing processes.")]
public class ProcessController(IProcessService processService, IProcessDocumentTemplateRightsService processDocumentTemplateRightsService, ILogger<ProcessController> logger)
    : ControllerBase
{
    /// <summary>
    /// Retrieves a list of processes for the authenticated user.
    /// </summary>
    /// <param name="latestVersion">If true, only the latest version of each process is returned.</param>
    /// <returns>A list of processes.</returns>
    /// <response code="200">Returns the list of processes.</response>
    /// <response code="401">If the user is not authenticated.</response>
    /// <response code="403">If the user lacks necessary rights.</response>
    /// <response code="500">If there is an internal server error.</response>
    [HttpGet("list")]
    [SwaggerOperation(Summary = "Retrieves a list of processes for the authenticated user.")]
    [ProducesResponseType(typeof(IReadOnlyCollection<List<ProcessListItemDTO>>), 200)]
    [ProducesResponseType(401)]
    [ProducesResponseType(403)]
    [ProducesResponseType(404)]
    [ProducesResponseType(500)]
    public async Task<IActionResult> ListProcesses([FromQuery] bool latestVersion = false)
    {
        var userName = JwtTokenHelper.GetUserName(HttpContext, logger, out var actionResult);

        if (string.IsNullOrEmpty(userName))
        {
            return actionResult;
        }

        logger.LogInformation("Fetching processes for user {UserName}", userName);
        var result = await processService.ListProcesses(new ListProcessRequest(userName, latestVersion));
        logger.LogInformation("Successfully fetched {Process} processes for user {UserName}", result, userName);

        return Ok(result);
    }

    /// <summary>
    /// Retrieves the permissions for a specific process.
    /// </summary>
    /// <param name="processId">The ID of the process.</param>
    /// <returns>A list of permissions for the specified process.</returns>
    /// <response code="200">Returns the list of permissions.</response>
    /// <response code="400">If the request is invalid.</response>
    /// <response code="401">If the user is not authenticated.</response>
    /// <response code="403">If the user lacks necessary rights.</response>
    /// <response code="500">If there is an internal server error.</response>
    [HttpGet("{processId:int}/permissions")]
    [SwaggerOperation(Summary = "Retrieves the permissions for a specific process.")]
    [ProducesResponseType(typeof(IEnumerable<ATRightAllowRight>), 200)]
    [ProducesResponseType(400)]
    [ProducesResponseType(401)]
    [ProducesResponseType(403)]
    [ProducesResponseType(404)]
    [ProducesResponseType(500)]
    public async Task<IActionResult> GetProcessPermissions([FromRoute] int processId)
    {
        var userName = JwtTokenHelper.GetUserName(HttpContext, logger, out var actionResult);

        if (string.IsNullOrEmpty(userName))
        {
            return actionResult;
        }

        var result = await processService.ListProcessesPermissions(new ListProcessAllowedRights(userName, processId));

        return Ok(result);
    }

    /// <summary>
    /// Retrieves the allowed templates for a specific process.
    /// </summary>
    /// <param name="processId">The ID of the process.</param>
    /// <returns>A list of allowed templates for the specified process.</returns>
    /// <response code="200">Returns the list of allowed templates.</response>
    /// <response code="400">If the request is invalid.</response>
    /// <response code="401">If the user is not authenticated.</response>
    /// <response code="500">If there is an internal server error.</response>
    [HttpGet("{processId:int}/allowed-templates")]
    [SwaggerOperation(Summary = "Retrieves the allowed templates for a specific process.")]
    [ProducesResponseType(typeof(IEnumerable<ProcessAllowedTemplateListDTO>), 200)]
    [ProducesResponseType(400)]
    [ProducesResponseType(401)]
    [ProducesResponseType(500)]
    public async Task<IActionResult> GetAllowedTemplatesForProcess([FromRoute] int processId)
    {
        var userName = JwtTokenHelper.GetUserName(HttpContext, logger, out var actionResult);

        if (string.IsNullOrEmpty(userName))
        {
            return actionResult;
        }
        
        var result = await processService.ListProcessesAllowedTemplates(new ListProcessAllowedTemplatesRequest(userName, processId));

        return Ok(result);
    }

    /// <summary>
    /// Updates the default template for a process.
    /// </summary>
    /// <param name="request">The request containing the process ID and the new default template information.</param>
    /// <returns>An IActionResult indicating the result of the operation.</returns>
    /// <response code="200">If the default template was successfully updated.</response>
    /// <response code="400">If the request is invalid.</response>
    /// <response code="401">If the user is not authenticated.</response>
    /// <response code="500">If there is an internal server error.</response>
    [HttpPatch("template")]
    [SwaggerOperation(Summary = "Updates the default template for a process.")]
    [ProducesResponseType(200)]
    [ProducesResponseType(400)]
    [ProducesResponseType(401)]
    [ProducesResponseType(500)]
    public async Task<IActionResult> UpdateProcessDefaultTemplate([FromBody] UpdateProcessDefaultTemplateRequest request)
    {
        await processService.UpdateProcessDefaultTemplate(request);
        return Ok();
    }

    /// <summary>
    /// Updates the limet templates for a process.
    /// </summary>
    /// <param name="request">The request containing the process ID and the new limet template information.</param>
    /// <returns>An IActionResult indicating the result of the operation.</returns>
    /// <response code="200">If the limet template was successfully updated.</response>
    /// <response code="400">If the request is invalid.</response>
    /// <response code="401">If the user is not authenticated.</response>
    /// <response code="500">If there is an internal server error.</response>
    [HttpPatch("limit-template")]
    [SwaggerOperation(Summary = "Updates the default template for a process.")]
    [ProducesResponseType(200)]
    [ProducesResponseType(400)]
    [ProducesResponseType(401)]
    [ProducesResponseType(500)]
    public async Task<IActionResult> UpdateProcessLimitTemplate([FromBody] List<UpdateProcessDefaultTemplateRequest> request)
    {
        if (request == null || !request.Any())
        {
            return BadRequest("The request must contain at least one item.");
        }
        await processDocumentTemplateRightsService.UpdateProcessLimitTemplate(request);
        return Ok();
    }
}