using e_suite.API.Common;
using e_suite.API.Common.models;
using e_suite.Utilities.Pagination;
using eSuite.API.security;
using eSuite.API.Utilities;
using eSuite.Core.Miscellaneous;
using eSuite.Core.Security;
using Microsoft.AspNetCore.Mvc;

namespace eSuite.API.Controllers;

/// <summary>
/// Allows creation and editing of security roles
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class RoleController : ESuiteControllerBase
{
    private IRoleManager _roleManager;

    /// <summary>
    /// Constructor for Role Controller
    /// </summary>
    /// <param name="roleManager"></param>
    public RoleController(IRoleManager roleManager)
    {
        _roleManager = roleManager;
    }

    /// <summary>
    /// Returns a list of all the roles in the system
    /// </summary>
    /// <remarks>This returns all the roles in the system that are not soft deleted. Use the Id or Guid column to specify a domain.</remarks>
    /// <param name="paging"></param>
    /// <param name="domain">The ID of the domain.  If null, will try to access all domains</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [Route("roles")]
    [HttpGet]
    [AccessKey(SecurityAccess.ViewRole)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetRoles(
        [FromQuery] Paging paging,
        [FromQuery] GeneralIdRef domain,
        CancellationToken cancellationToken = default!
    )
    {
        var result = await _roleManager.GetRoles(paging, domain, cancellationToken);
        return Ok(result);
    }

    /// <summary>
    /// Returns the details of a specific role
    /// </summary>
    /// <remarks>This returns all the sequences in the system that are not soft deleted.</remarks>
    [Route("role")]
    [HttpGet]
    [AccessKey(SecurityAccess.ViewRole)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetRole(
        [FromQuery] long? id,
        [FromQuery] Guid? guid,
        CancellationToken cancellationToken = default!
    )
    {
        var generalIdRef = new GeneralIdRef
        {
            Id = id,
            Guid = guid
        };

        var result = await _roleManager.GetRole(generalIdRef, cancellationToken);

        return Ok(result);
    }

    /// <summary>
    /// Create a role
    /// </summary>
    /// <param name="createRole">Contains the data required to create a role</param>
    /// <param name="cancellationToken"></param>
    [Route("role")]
    [HttpPost]
    [AccessKey(SecurityAccess.AddRole)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> CreateRole(
        [FromBody] CreateRole createRole,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.CreateRole(AuditUserDetails, createRole, cancellationToken);
        return Ok();
    }

    /// <summary>
    /// Edit a role
    /// </summary>
    /// <remarks>All the fields can be edited except the Id and Guid field</remarks>
    /// <param name="editRole">Contains the details of the updated sequence</param>
    /// <param name="cancellationToken"></param>
    [Route("role")]
    [HttpPut]
    [AccessKey(SecurityAccess.EditRole)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> EditRole(
        [FromBody] EditRole editRole,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.EditRole(AuditUserDetails, editRole, cancellationToken);
        return Ok();
    }

    /// <summary>
    /// Deletes a role
    /// </summary>
    /// <remarks>This will perform a soft delete action.</remarks>
    /// <param name="generalIdRef">Either the id or the Guid of the role</param>
    /// <param name="cancellationToken"></param>
    [Route("role")]
    [HttpDelete]
    [AccessKey(SecurityAccess.DeleteRole)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> DeleteRole(
        GeneralIdRef generalIdRef,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.DeleteRole(AuditUserDetails, generalIdRef, cancellationToken);
        return Ok();
    }
    
    /// <summary>
    /// Returns a list of all the roles in the system
    /// </summary>
    /// /// <remarks>This returns all the roles in the system that are not soft deleted. Use the Id or Guid column to specify a domain.</remarks>
    /// <param name="paging"></param>
    /// <param name="roleId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [Route("roleUsers")]
    [HttpGet]
    [AccessKey(SecurityAccess.ViewRoleUsers)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetRoleUsers(
        [FromQuery] Paging paging,
        [FromQuery] GeneralIdRef roleId,
        CancellationToken cancellationToken = default!
    )
    {
        var result = await _roleManager.GetRoleUsers(paging, roleId, cancellationToken);
        return Ok(result);
    }

    /// <summary>
    /// Deletes a role
    /// </summary>
    /// <remarks>This will perform a soft delete action.</remarks>
    /// <param name="userRoleIds">The ids needed to identify which role and user combination</param>
    /// <param name="cancellationToken"></param>
    [Route("roleUsers")]
    [HttpPost]
    [AccessKey(SecurityAccess.AddRoleUser)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> AddRoleUser(
        [FromBody] UserRoleIds userRoleIds,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.AddRoleUser(AuditUserDetails, userRoleIds, cancellationToken);
        return Ok();
    }

    /// <summary>
    /// Deletes a role
    /// </summary>
    /// <remarks>This will perform a soft delete action.</remarks>
    /// <param name="userRoleIds">The ids needed to identify which role and user combination</param>
    /// <param name="cancellationToken"></param>
    [Route("roleUsers")]
    [HttpDelete]
    [AccessKey(SecurityAccess.DeleteRoleUser)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> DeleteRoleUser(
        [FromBody] UserRoleIds userRoleIds,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.DeleteRoleUser(AuditUserDetails, userRoleIds, cancellationToken);
        return Ok();
    }

    /// <summary>
    /// Returns a list of all the access rights available in the system.
    /// </summary>
    /// <remarks>This is the master list of access rights that may be assigned to roles.</remarks>
    /// <param name="paging"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [Route("accessList")]
    [HttpGet]
    [AccessKey(SecurityAccess.ViewAccessList)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetAccessList(
        [FromQuery] Paging paging,
        CancellationToken cancellationToken = default!
    )
    {
        var result = await _roleManager.GetAccessList(paging, cancellationToken);
        return Ok(result);
    }

    /// <summary>
    /// Returns a list of all the access rights assigned to roles.
    /// </summary>
    /// <param name="paging"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [Route("roleAccess")]
    [HttpGet]
    [AccessKey(SecurityAccess.ViewRoleAccess)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetRoleAccess(
        [FromQuery] Paging paging,
        CancellationToken cancellationToken = default!
    )
    {
        var result = await _roleManager.GetRoleAccess(paging, cancellationToken);
        return Ok(result);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="accessToAdd"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [Route("roleAccess")]
    [HttpPost]
    [AccessKey(SecurityAccess.EditRoleAccess)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> PostRoleAccess(
        [FromBody] AddRoleSecurityAccess accessToAdd,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.AddRoleSecurityAccess(AuditUserDetails, accessToAdd, cancellationToken);
        return Ok();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="accessToRemove"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [Route("roleAccess")]
    [HttpDelete]
    [AccessKey(SecurityAccess.Everyone)]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<IActionResult> DeleteRoleAccess(
        [FromBody] DeleteRoleSecurityAccess accessToRemove,
        CancellationToken cancellationToken = default!
    )
    {
        await _roleManager.DeleteRoleSecurityAccess(AuditUserDetails, accessToRemove, cancellationToken);
        return Ok();
    }
}