// EN: Query to get merchant details for admin.
// VI: Query để lấy chi tiết merchant cho admin.

using MediatR;
using Microsoft.EntityFrameworkCore;
using MerchantService.Domain.AggregatesModel.MerchantAggregate;
using MerchantService.Domain.AggregatesModel.ShopAggregate;
using MerchantService.Domain.Exceptions;
using MerchantService.Infrastructure;

namespace MerchantService.API.Application.Queries.Admin;

public record GetMerchantDetailQuery(Guid MerchantId) : IRequest<AdminMerchantDetailDto>;

/// <summary>
/// EN: Handler — joins with enum tables to avoid NullRef on Ignored navigation properties.
/// VI: Handler — join với bảng enum để tránh NullRef trên navigation properties bị Ignore.
/// </summary>
public class GetMerchantDetailQueryHandler : IRequestHandler<GetMerchantDetailQuery, AdminMerchantDetailDto>
{
    private readonly MerchantServiceContext _context;
    private static readonly string[] PlanNames = ["Starter", "Growth", "Pro", "Enterprise"];

    public GetMerchantDetailQueryHandler(MerchantServiceContext context)
    {
        _context = context;
    }

    public async Task<AdminMerchantDetailDto> Handle(
        GetMerchantDetailQuery request,
        CancellationToken cancellationToken)
    {
        // EN: Fetch raw data with joins (avoid Ignored navigation property NullRef)
        // VI: Lấy raw data với joins (tránh NullRef từ navigation property bị Ignore)
        var raw = await _context.Merchants
            .AsNoTracking()
            .Where(m => m.Id == request.MerchantId && !EF.Property<bool>(m, "_isDeleted"))
            .Join(_context.Set<MerchantType>(), m => m.TypeId, t => t.Id, (m, t) => new { m, TypeName = t.Name })
            .Join(_context.Set<MerchantStatus>(), x => x.m.StatusId, s => s.Id, (x, s) => new { x.m, x.TypeName, StatusName = s.Name })
            .Join(_context.Set<VerificationStatus>(), x => x.m.VerificationStatusId, v => v.Id, (x, v) => new { x.m, x.TypeName, x.StatusName, VerifName = v.Name })
            .Select(x => new
            {
                x.m.Id,
                UserId = EF.Property<Guid>(x.m, "_userId"),
                BusinessName = EF.Property<string>(x.m, "_businessName"),
                x.TypeName,
                x.StatusName,
                x.VerifName,
                PlanId = EF.Property<int>(x.m, "_subscriptionPlanId"),
                CreatedAt = EF.Property<DateTime>(x.m, "_createdAt"),
                UpdatedAt = EF.Property<DateTime?>(x.m, "_updatedAt"),
                x.m.VerifiedAt,
                x.m.VerifiedBy,
            })
            .FirstOrDefaultAsync(cancellationToken)
            ?? throw new DomainException($"Merchant {request.MerchantId} not found");

        // EN: Fetch shops for this merchant with status names
        // VI: Lấy danh sách shops của merchant với tên status
        var shops = await _context.Shops
            .AsNoTracking()
            .Where(s => EF.Property<Guid>(s, "_merchantId") == request.MerchantId
                     && !EF.Property<bool>(s, "_isDeleted"))
            .Join(_context.Set<ShopStatus>(), s => s.StatusId, st => st.Id, (s, st) => new { s, StatusName = st.Name })
            .Join(_context.Set<BusinessCategory>(), x => x.s.CategoryId, c => c.Id, (x, c) => new { x.s, x.StatusName, CategoryName = c.Name })
            .Select(x => new AdminShopSummaryDto(
                x.s.Id,
                EF.Property<string>(x.s, "_name"),
                x.CategoryName,
                x.StatusName,
                EF.Property<DateTime>(x.s, "_createdAt")))
            .ToListAsync(cancellationToken);

        var staffCount = await _context.MerchantStaff
            .CountAsync(s => s.MerchantId == request.MerchantId, cancellationToken);

        return new AdminMerchantDetailDto(
            raw.Id,
            raw.UserId,
            raw.BusinessName,
            raw.TypeName,
            raw.StatusName,
            raw.VerifName,
            null, // BusinessInfo
            null, // SettlementConfig
            shops.Count,
            staffCount,
            raw.PlanId,
            PlanNames.ElementAtOrDefault(raw.PlanId) ?? "Starter",
            raw.CreatedAt,
            raw.UpdatedAt,
            raw.VerifiedAt,
            raw.VerifiedBy,
            shops);
    }
}
