using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using IamService.API.Application.Common;
using IamService.API.Application.Commands.AccessRequests;
using IamService.API.Application.Queries.AccessRequests;

namespace IamService.API.Controllers;

/// <summary>
/// EN: Access request management controller.
/// VI: Controller quản lý yêu cầu truy cập.
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/access-requests")]
[Authorize(AuthenticationSchemes = "Bearer")]
[Authorize(Policy = "RequireAdmin")]
[SwaggerTag("Access request management - requires Admin role")]
public class AccessRequestsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<AccessRequestsController> _logger;

    public AccessRequestsController(IMediator mediator, ILogger<AccessRequestsController> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    /// <summary>
    /// EN: Create a new access request.
    /// VI: Tạo yêu cầu truy cập mới.
    /// </summary>
    [HttpPost]
    [SwaggerOperation(Summary = "Create access request", OperationId = "CreateAccessRequest")]
    [SwaggerResponse(StatusCodes.Status201Created, "Request created", typeof(ApiResponse<AccessRequestResponse>))]
    public async Task<IActionResult> CreateAccessRequest(
        [FromBody] CreateAccessRequestRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new CreateAccessRequestCommand(
            request.RequesterId,
            request.ResourceType,
            request.ResourceId,
            request.RequestedPermission,
            request.Justification,
            request.Priority,
            request.ApproverIds);

        var result = await _mediator.Send(command, cancellationToken);

        return CreatedAtAction(nameof(GetAccessRequestById), new { id = result.Id },
            ApiResponse<AccessRequestResponse>.Ok(new AccessRequestResponse
            {
                Id = result.Id,
                Status = result.Status,
                CreatedAt = result.CreatedAt
            }));
    }

    /// <summary>
    /// EN: Get access request by ID.
    /// VI: Lấy yêu cầu truy cập theo ID.
    /// </summary>
    [HttpGet("{id:guid}")]
    [SwaggerOperation(Summary = "Get access request by ID", OperationId = "GetAccessRequestById")]
    [SwaggerResponse(StatusCodes.Status200OK, "Request found", typeof(ApiResponse<AccessRequestDto>))]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Request not found")]
    public async Task<IActionResult> GetAccessRequestById(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetAccessRequestByIdQuery(id), cancellationToken);
        if (result == null)
            return NotFound(ApiResponse<AccessRequestDto>.Fail("REQUEST_NOT_FOUND", $"Access request {id} not found."));

        return Ok(ApiResponse<AccessRequestDto>.Ok(result));
    }

    /// <summary>
    /// EN: Get my access requests.
    /// VI: Lấy yêu cầu truy cập của tôi.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get my access requests", OperationId = "GetMyAccessRequests")]
    [SwaggerResponse(StatusCodes.Status200OK, "Requests returned", typeof(ApiResponse<IEnumerable<AccessRequestDto>>))]
    public async Task<IActionResult> GetMyAccessRequests(
        [FromQuery] Guid requesterId,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetMyAccessRequestsQuery(requesterId), cancellationToken);
        return Ok(ApiResponse<IEnumerable<AccessRequestDto>>.Ok(result));
    }

    /// <summary>
    /// EN: Get pending approvals for me.
    /// VI: Lấy các yêu cầu đang chờ tôi phê duyệt.
    /// </summary>
    [HttpGet("pending")]
    [SwaggerOperation(Summary = "Get pending approvals", OperationId = "GetPendingApprovals")]
    [SwaggerResponse(StatusCodes.Status200OK, "Pending approvals returned", typeof(ApiResponse<IEnumerable<AccessRequestDto>>))]
    public async Task<IActionResult> GetPendingApprovals(
        [FromQuery] Guid approverId,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetPendingApprovalsQuery(approverId), cancellationToken);
        return Ok(ApiResponse<IEnumerable<AccessRequestDto>>.Ok(result));
    }

    /// <summary>
    /// EN: Submit access request for approval.
    /// VI: Gửi yêu cầu truy cập để phê duyệt.
    /// </summary>
    [HttpPost("{id:guid}/submit")]
    [SwaggerOperation(Summary = "Submit access request", OperationId = "SubmitAccessRequest")]
    [SwaggerResponse(StatusCodes.Status200OK, "Request submitted")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Request not found")]
    public async Task<IActionResult> SubmitAccessRequest(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new SubmitAccessRequestCommand(id), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Access request submitted successfully." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("REQUEST_NOT_FOUND", ex.Message));
        }
    }

    /// <summary>
    /// EN: Approve access request.
    /// VI: Phê duyệt yêu cầu truy cập.
    /// </summary>
    [HttpPost("{id:guid}/approve")]
    [SwaggerOperation(Summary = "Approve access request", OperationId = "ApproveAccessRequest")]
    [SwaggerResponse(StatusCodes.Status200OK, "Request approved")]
    [SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid operation")]
    public async Task<IActionResult> ApproveAccessRequest(
        [FromRoute] Guid id,
        [FromBody] ApproveRejectRequest request,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new ApproveAccessRequestCommand(id, request.ApproverId, request.Comments), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Access request approved." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("REQUEST_NOT_FOUND", ex.Message));
        }
        catch (Exception ex)
        {
            return BadRequest(ApiResponse<object>.Fail("INVALID_OPERATION", ex.Message));
        }
    }

    /// <summary>
    /// EN: Reject access request.
    /// VI: Từ chối yêu cầu truy cập.
    /// </summary>
    [HttpPost("{id:guid}/reject")]
    [SwaggerOperation(Summary = "Reject access request", OperationId = "RejectAccessRequest")]
    [SwaggerResponse(StatusCodes.Status200OK, "Request rejected")]
    public async Task<IActionResult> RejectAccessRequest(
        [FromRoute] Guid id,
        [FromBody] ApproveRejectRequest request,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new RejectAccessRequestCommand(id, request.ApproverId, request.Comments), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Access request rejected." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("REQUEST_NOT_FOUND", ex.Message));
        }
        catch (Exception ex)
        {
            return BadRequest(ApiResponse<object>.Fail("INVALID_OPERATION", ex.Message));
        }
    }

    /// <summary>
    /// EN: Cancel access request.
    /// VI: Hủy yêu cầu truy cập.
    /// </summary>
    [HttpDelete("{id:guid}")]
    [SwaggerOperation(Summary = "Cancel access request", OperationId = "CancelAccessRequest")]
    [SwaggerResponse(StatusCodes.Status200OK, "Request cancelled")]
    public async Task<IActionResult> CancelAccessRequest(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new CancelAccessRequestCommand(id), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Access request cancelled." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("REQUEST_NOT_FOUND", ex.Message));
        }
        catch (Exception ex)
        {
            return BadRequest(ApiResponse<object>.Fail("INVALID_OPERATION", ex.Message));
        }
    }
}

#region Request/Response Models

public class CreateAccessRequestRequest
{
    public Guid RequesterId { get; set; }
    /// <example>Organization</example>
    public string ResourceType { get; set; } = string.Empty;
    public Guid ResourceId { get; set; }
    /// <example>Admin</example>
    public string RequestedPermission { get; set; } = string.Empty;
    public string? Justification { get; set; }
    /// <example>2</example>
    public int? Priority { get; set; } // 1=Low, 2=Medium, 3=High, 4=Critical
    public List<Guid> ApproverIds { get; set; } = [];
}

public class ApproveRejectRequest
{
    public Guid ApproverId { get; set; }
    public string? Comments { get; set; }
}

public class AccessRequestResponse
{
    public Guid Id { get; set; }
    public string Status { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
}

#endregion
