// EN: Staff queries.
// VI: Queries cho nhân viên.

using MediatR;
using MerchantService.Domain.AggregatesModel.MerchantAggregate;
using MerchantService.Domain.AggregatesModel.MerchantStaffAggregate;
using MerchantService.Domain.Exceptions;

namespace MerchantService.API.Application.Queries.Staff;

#region Get My Staff Query

/// <summary>
/// EN: Query to get current merchant's staff list.
/// VI: Query để lấy danh sách nhân viên của merchant hiện tại.
/// </summary>
public record GetMyStaffQuery : IRequest<IReadOnlyList<StaffDto>>;

/// <summary>
/// EN: Handler for GetMyStaffQuery.
/// VI: Handler cho GetMyStaffQuery.
/// </summary>
public class GetMyStaffQueryHandler : IRequestHandler<GetMyStaffQuery, IReadOnlyList<StaffDto>>
{
    private readonly IMerchantRepository _merchantRepository;
    private readonly IMerchantStaffRepository _staffRepository;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public GetMyStaffQueryHandler(
        IMerchantRepository merchantRepository,
        IMerchantStaffRepository staffRepository,
        IHttpContextAccessor httpContextAccessor)
    {
        _merchantRepository = merchantRepository;
        _staffRepository = staffRepository;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<IReadOnlyList<StaffDto>> Handle(GetMyStaffQuery request, CancellationToken cancellationToken)
    {
        var userId = GetUserId();
        var merchant = await _merchantRepository.GetByUserIdAsync(userId, cancellationToken)
            ?? throw new DomainException("Merchant not found");

        var staffList = await _staffRepository.GetByMerchantIdAsync(merchant.Id, cancellationToken);

        return staffList.Select(s => new StaffDto
        {
            Id = s.Id,
            Email = s.Email ?? string.Empty,
            EmployeeCode = s.EmployeeCode,
            Phone = s.Phone,
            Role = s.Role.Name,
            Status = s.Status.Name,
            Permissions = (int)s.Permissions,
            HasPinCode = !string.IsNullOrEmpty(s.PinCodeHash),
            CreatedAt = s.CreatedAt,
            UpdatedAt = s.UpdatedAt,
            ShopAssignments = s.ShopAssignments.Select(sm => new ShopAssignmentDto
            {
                ShopId = sm.ShopId,
                ShopRole = sm.Role.Name,
                BranchId = sm.BranchId
            }).ToList()
        }).ToList();
    }

    private Guid GetUserId()
    {
        var userIdClaim = _httpContextAccessor.HttpContext?.User.FindFirst("sub")?.Value
            ?? _httpContextAccessor.HttpContext?.User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
        if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
            throw new DomainException("User not authenticated");
        return userId;
    }
}

#endregion

#region Staff DTOs

/// <summary>
/// EN: Staff DTO.
/// VI: DTO nhân viên.
/// </summary>
public record StaffDto
{
    public Guid Id { get; init; }
    public string Email { get; init; } = null!;
    public string? EmployeeCode { get; init; }
    public string? Phone { get; init; }
    public string Role { get; init; } = null!;
    public string Status { get; init; } = null!;
    public int Permissions { get; init; }
    public bool HasPinCode { get; init; }
    public DateTime CreatedAt { get; init; }
    public DateTime? UpdatedAt { get; init; }
    public List<ShopAssignmentDto> ShopAssignments { get; init; } = [];
}

/// <summary>
/// EN: Shop assignment DTO.
/// VI: DTO gán shop.
/// </summary>
public record ShopAssignmentDto
{
    public Guid ShopId { get; init; }
    public string ShopRole { get; init; } = null!;
    public Guid? BranchId { get; init; }
}

#endregion
