using MediatR;
using IamService.Domain.AggregatesModel.AccessRequestAggregate;

namespace IamService.API.Application.Queries.AccessRequests;

/// <summary>
/// EN: Handler for GetAccessRequestByIdQuery.
/// VI: Handler cho GetAccessRequestByIdQuery.
/// </summary>
public class GetAccessRequestByIdQueryHandler : IRequestHandler<GetAccessRequestByIdQuery, AccessRequestDto?>
{
    private readonly IAccessRequestRepository _repository;

    public GetAccessRequestByIdQueryHandler(IAccessRequestRepository repository)
    {
        _repository = repository;
    }

    public async Task<AccessRequestDto?> Handle(GetAccessRequestByIdQuery request, CancellationToken cancellationToken)
    {
        var accessRequest = await _repository.GetByIdWithApproversAsync(request.Id, cancellationToken);
        return accessRequest != null ? MapToDto(accessRequest) : null;
    }

    private static AccessRequestDto MapToDto(AccessRequest request) => new(
        request.Id,
        request.RequesterId,
        request.ResourceType,
        request.ResourceId,
        request.RequestedPermission,
        request.Justification,
        request.Status.Name,
        request.Priority.Name,
        request.CreatedAt,
        request.SubmittedAt,
        request.ResolvedAt,
        request.ExpiresAt,
        request.Approvers.Select(a => new AccessRequestApproverDto(
            a.Id,
            a.UserId,
            a.Order,
            a.Status.Name,
            a.RespondedAt,
            a.Comments)));
}

/// <summary>
/// EN: Handler for GetMyAccessRequestsQuery.
/// VI: Handler cho GetMyAccessRequestsQuery.
/// </summary>
public class GetMyAccessRequestsQueryHandler : IRequestHandler<GetMyAccessRequestsQuery, IEnumerable<AccessRequestDto>>
{
    private readonly IAccessRequestRepository _repository;

    public GetMyAccessRequestsQueryHandler(IAccessRequestRepository repository)
    {
        _repository = repository;
    }

    public async Task<IEnumerable<AccessRequestDto>> Handle(GetMyAccessRequestsQuery request, CancellationToken cancellationToken)
    {
        var requests = await _repository.GetByRequesterIdAsync(request.RequesterId, cancellationToken);
        return requests.Select(MapToDto);
    }

    private static AccessRequestDto MapToDto(AccessRequest request) => new(
        request.Id,
        request.RequesterId,
        request.ResourceType,
        request.ResourceId,
        request.RequestedPermission,
        request.Justification,
        request.Status.Name,
        request.Priority.Name,
        request.CreatedAt,
        request.SubmittedAt,
        request.ResolvedAt,
        request.ExpiresAt,
        request.Approvers.Select(a => new AccessRequestApproverDto(
            a.Id,
            a.UserId,
            a.Order,
            a.Status.Name,
            a.RespondedAt,
            a.Comments)));
}

/// <summary>
/// EN: Handler for GetPendingApprovalsQuery.
/// VI: Handler cho GetPendingApprovalsQuery.
/// </summary>
public class GetPendingApprovalsQueryHandler : IRequestHandler<GetPendingApprovalsQuery, IEnumerable<AccessRequestDto>>
{
    private readonly IAccessRequestRepository _repository;

    public GetPendingApprovalsQueryHandler(IAccessRequestRepository repository)
    {
        _repository = repository;
    }

    public async Task<IEnumerable<AccessRequestDto>> Handle(GetPendingApprovalsQuery request, CancellationToken cancellationToken)
    {
        var requests = await _repository.GetPendingByApproverIdAsync(request.ApproverId, cancellationToken);
        return requests.Select(MapToDto);
    }

    private static AccessRequestDto MapToDto(AccessRequest request) => new(
        request.Id,
        request.RequesterId,
        request.ResourceType,
        request.ResourceId,
        request.RequestedPermission,
        request.Justification,
        request.Status.Name,
        request.Priority.Name,
        request.CreatedAt,
        request.SubmittedAt,
        request.ResolvedAt,
        request.ExpiresAt,
        request.Approvers.Select(a => new AccessRequestApproverDto(
            a.Id,
            a.UserId,
            a.Order,
            a.Status.Name,
            a.RespondedAt,
            a.Comments)));
}
