// EN: Handlers for Shop queries.
// VI: Handlers cho Shop queries.

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

namespace MerchantService.API.Application.Queries.Shops;

/// <summary>
/// EN: Handler for getting current merchant's shops.
/// VI: Handler để lấy danh sách shops của merchant hiện tại.
/// </summary>
public class GetMyShopsQueryHandler : IRequestHandler<GetMyShopsQuery, IReadOnlyList<ShopDto>>
{
    private readonly IMerchantRepository _merchantRepository;
    private readonly IShopRepository _shopRepository;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public GetMyShopsQueryHandler(
        IMerchantRepository merchantRepository,
        IShopRepository shopRepository,
        IHttpContextAccessor httpContextAccessor)
    {
        _merchantRepository = merchantRepository;
        _shopRepository = shopRepository;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<IReadOnlyList<ShopDto>> Handle(GetMyShopsQuery request, CancellationToken cancellationToken)
    {
        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");
        }

        var merchant = await _merchantRepository.GetByUserIdAsync(userId, cancellationToken);
        if (merchant == null)
        {
            return [];
        }

        var shops = await _shopRepository.GetByMerchantIdAsync(merchant.Id, cancellationToken);

        return shops.Select(s => new ShopDto
        {
            Id = s.Id,
            Name = s.Name,
            Slug = s.Slug,
            Type = s.Type.Name,
            Category = s.Category.Name,
            Status = s.Status.Name,
            LogoUrl = s.LogoUrl,
            BranchCount = s.Branches.Count,
            CreatedAt = s.CreatedAt
        }).ToList();
    }
}

/// <summary>
/// EN: Handler for getting shop by ID.
/// VI: Handler để lấy shop theo ID.
/// </summary>
public class GetShopByIdQueryHandler : IRequestHandler<GetShopByIdQuery, ShopDetailDto?>
{
    private readonly IShopRepository _shopRepository;

    public GetShopByIdQueryHandler(IShopRepository shopRepository)
    {
        _shopRepository = shopRepository;
    }

    public async Task<ShopDetailDto?> Handle(GetShopByIdQuery request, CancellationToken cancellationToken)
    {
        var shop = await _shopRepository.GetByIdWithBranchesAsync(request.ShopId, cancellationToken);
        return shop != null ? MapToDetailDto(shop) : null;
    }

    private static ShopDetailDto MapToDetailDto(Shop shop)
    {
        return new ShopDetailDto
        {
            Id = shop.Id,
            MerchantId = shop.MerchantId,
            Name = shop.Name,
            Slug = shop.Slug,
            Type = shop.Type.Name,
            Category = shop.Category.Name,
            Status = shop.Status.Name,
            Description = shop.Description,
            LogoUrl = shop.LogoUrl,
            CoverImageUrl = shop.CoverImageUrl,
            ContactInfo = new ContactInfoDto
            {
                Phone = shop.ContactInfo.Phone,
                Email = shop.ContactInfo.Email,
                Website = shop.ContactInfo.Website
            },
            OperatingHours = shop.OperatingHours != null ? new OperatingHoursDto
            {
                OpenTime = shop.OperatingHours.OpenTime.ToString("HH:mm"),
                CloseTime = shop.OperatingHours.CloseTime.ToString("HH:mm"),
                OpenDays = shop.OperatingHours.OpenDays.Select(d => d.ToString()).ToList()
            } : null,
            Branches = shop.Branches.Select(b => new ShopBranchDto
            {
                Id = b.Id,
                Name = b.Name,
                Code = b.Code,
                Address = new AddressDto
                {
                    Street = b.Address.Street,
                    Ward = b.Address.Ward,
                    District = b.Address.District,
                    City = b.Address.City,
                    Province = b.Address.Province,
                    FullAddress = b.Address.FullAddress
                },
                Location = b.Location != null ? new GeoLocationDto
                {
                    Latitude = b.Location.Latitude,
                    Longitude = b.Location.Longitude
                } : null,
                Phone = b.Phone,
                IsActive = b.IsActive
            }).ToList(),
            CreatedAt = shop.CreatedAt,
            UpdatedAt = shop.UpdatedAt
        };
    }
}

/// <summary>
/// EN: Handler for getting shop by slug.
/// VI: Handler để lấy shop theo slug.
/// </summary>
public class GetShopBySlugQueryHandler : IRequestHandler<GetShopBySlugQuery, ShopDetailDto?>
{
    private readonly IShopRepository _shopRepository;

    public GetShopBySlugQueryHandler(IShopRepository shopRepository)
    {
        _shopRepository = shopRepository;
    }

    public async Task<ShopDetailDto?> Handle(GetShopBySlugQuery request, CancellationToken cancellationToken)
    {
        var shop = await _shopRepository.GetBySlugAsync(request.Slug, cancellationToken);
        if (shop == null)
        {
            return null;
        }

        // EN: Get shop with branches
        // VI: Lấy shop với các chi nhánh
        var shopWithBranches = await _shopRepository.GetByIdWithBranchesAsync(shop.Id, cancellationToken);
        return shopWithBranches != null ? new ShopDetailDto
        {
            Id = shopWithBranches.Id,
            MerchantId = shopWithBranches.MerchantId,
            Name = shopWithBranches.Name,
            Slug = shopWithBranches.Slug,
            Type = shopWithBranches.Type.Name,
            Category = shopWithBranches.Category.Name,
            Status = shopWithBranches.Status.Name,
            Description = shopWithBranches.Description,
            LogoUrl = shopWithBranches.LogoUrl,
            CoverImageUrl = shopWithBranches.CoverImageUrl,
            ContactInfo = new ContactInfoDto
            {
                Phone = shopWithBranches.ContactInfo.Phone,
                Email = shopWithBranches.ContactInfo.Email,
                Website = shopWithBranches.ContactInfo.Website
            },
            Branches = shopWithBranches.Branches.Where(b => b.IsActive).Select(b => new ShopBranchDto
            {
                Id = b.Id,
                Name = b.Name,
                Code = b.Code,
                Address = new AddressDto
                {
                    Street = b.Address.Street,
                    Ward = b.Address.Ward,
                    District = b.Address.District,
                    City = b.Address.City,
                    Province = b.Address.Province,
                    FullAddress = b.Address.FullAddress
                },
                Location = b.Location != null ? new GeoLocationDto
                {
                    Latitude = b.Location.Latitude,
                    Longitude = b.Location.Longitude
                } : null,
                Phone = b.Phone,
                IsActive = b.IsActive
            }).ToList(),
            CreatedAt = shopWithBranches.CreatedAt,
            UpdatedAt = shopWithBranches.UpdatedAt
        } : null;
    }
}
