using System.Globalization;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Application.App.Members.Commands;
using TakeoutSaaS.Application.App.Members.Dto;
using TakeoutSaaS.Application.App.Members.Queries;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Infrastructure.App.Persistence;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;
using TakeoutSaaS.TenantApi.Contracts.Member;

namespace TakeoutSaaS.TenantApi.Controllers;

/// <summary>
/// 会员管理列表与详情。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/tenant/v{version:apiVersion}/member/list")]
public sealed class MemberController(
    IMediator mediator,
    TakeoutAppDbContext dbContext,
    StoreContextService storeContextService)
    : BaseApiController
{
    private const string ViewPermission = "tenant:member:view";
    private const string ManagePermission = "tenant:member:manage";

    /// <summary>
    /// 获取会员列表。
    /// </summary>
    [HttpGet("list")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberListResultResponse>> List(
        [FromQuery] MemberListRequest request,
        CancellationToken cancellationToken)
    {
        var visibleStoreIds = await ResolveVisibleStoreIdsAsync(request.StoreId, cancellationToken);

        var result = await mediator.Send(new SearchMemberListQuery
        {
            VisibleStoreIds = visibleStoreIds,
            Keyword = request.Keyword,
            TierId = StoreApiHelpers.ParseSnowflakeOrNull(request.TierId),
            Page = Math.Max(1, request.Page),
            PageSize = Math.Clamp(request.PageSize, 1, 200)
        }, cancellationToken);

        return ApiResponse<MemberListResultResponse>.Ok(new MemberListResultResponse
        {
            Items = result.Items.Select(MapListItem).ToList(),
            Total = result.TotalCount,
            Page = result.Page,
            PageSize = result.PageSize
        });
    }

    /// <summary>
    /// 获取会员列表统计。
    /// </summary>
    [HttpGet("stats")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberListStatsResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberListStatsResponse>> Stats(
        [FromQuery] MemberListFilterRequest request,
        CancellationToken cancellationToken)
    {
        var visibleStoreIds = await ResolveVisibleStoreIdsAsync(request.StoreId, cancellationToken);

        var result = await mediator.Send(new GetMemberListStatsQuery
        {
            VisibleStoreIds = visibleStoreIds,
            Keyword = request.Keyword,
            TierId = StoreApiHelpers.ParseSnowflakeOrNull(request.TierId)
        }, cancellationToken);

        return ApiResponse<MemberListStatsResponse>.Ok(new MemberListStatsResponse
        {
            TotalMembers = result.TotalMembers,
            MonthlyNewMembers = result.MonthlyNewMembers,
            ActiveMembers = result.ActiveMembers,
            DormantMembers = result.DormantMembers
        });
    }

    /// <summary>
    /// 获取会员详情。
    /// </summary>
    [HttpGet("detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberDetailResponse>> Detail(
        [FromQuery] MemberDetailRequest request,
        CancellationToken cancellationToken)
    {
        var visibleStoreIds = await ResolveVisibleStoreIdsAsync(request.StoreId, cancellationToken);

        var result = await mediator.Send(new GetMemberDetailQuery
        {
            VisibleStoreIds = visibleStoreIds,
            MemberId = StoreApiHelpers.ParseRequiredSnowflake(request.MemberId, nameof(request.MemberId))
        }, cancellationToken);

        if (result is null)
        {
            return ApiResponse<MemberDetailResponse>.Error(ErrorCodes.NotFound, "会员不存在");
        }

        return ApiResponse<MemberDetailResponse>.Ok(MapDetail(result));
    }

    /// <summary>
    /// 保存会员标签。
    /// </summary>
    [HttpPost("tags")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> SaveTags(
        [FromBody] SaveMemberTagsRequest request,
        CancellationToken cancellationToken)
    {
        _ = await ResolveVisibleStoreIdsAsync(request.StoreId, cancellationToken);

        await mediator.Send(new SaveMemberTagsCommand
        {
            MemberId = StoreApiHelpers.ParseRequiredSnowflake(request.MemberId, nameof(request.MemberId)),
            Tags = (request.Tags ?? []).ToList()
        }, cancellationToken);

        return ApiResponse<object>.Ok(null);
    }

    /// <summary>
    /// 导出会员列表 CSV。
    /// </summary>
    [HttpGet("export")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberExportResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberExportResponse>> Export(
        [FromQuery] MemberListFilterRequest request,
        CancellationToken cancellationToken)
    {
        var visibleStoreIds = await ResolveVisibleStoreIdsAsync(request.StoreId, cancellationToken);

        var result = await mediator.Send(new ExportMemberCsvQuery
        {
            VisibleStoreIds = visibleStoreIds,
            Keyword = request.Keyword,
            TierId = StoreApiHelpers.ParseSnowflakeOrNull(request.TierId)
        }, cancellationToken);

        return ApiResponse<MemberExportResponse>.Ok(new MemberExportResponse
        {
            FileName = result.FileName,
            FileContentBase64 = result.FileContentBase64,
            TotalCount = result.TotalCount
        });
    }

    private async Task<IReadOnlyCollection<long>> ResolveVisibleStoreIdsAsync(
        string? storeId,
        CancellationToken cancellationToken)
    {
        var (tenantId, merchantId) = StoreApiHelpers.GetTenantMerchantContext(storeContextService);

        if (!string.IsNullOrWhiteSpace(storeId))
        {
            var parsedStoreId = StoreApiHelpers.ParseRequiredSnowflake(storeId, nameof(storeId));
            await StoreApiHelpers.EnsureStoreAccessibleAsync(
                dbContext,
                tenantId,
                merchantId,
                parsedStoreId,
                cancellationToken);
            return [parsedStoreId];
        }

        var allStoreIds = await dbContext.Stores
            .AsNoTracking()
            .Where(item => item.TenantId == tenantId && item.MerchantId == merchantId)
            .Select(item => item.Id)
            .OrderBy(item => item)
            .ToListAsync(cancellationToken);

        if (allStoreIds.Count == 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "当前商户下不存在可用门店");
        }

        return allStoreIds;
    }

    private static MemberListItemResponse MapListItem(MemberListItemDto source)
    {
        return new MemberListItemResponse
        {
            MemberId = source.MemberId.ToString(),
            Name = source.Name,
            AvatarText = source.AvatarText,
            AvatarColor = source.AvatarColor,
            MobileMasked = source.MobileMasked,
            TierId = source.TierId?.ToString(),
            TierName = source.TierName,
            TierColorHex = source.TierColorHex,
            TotalAmount = source.TotalAmount,
            OrderCount = source.OrderCount,
            LastOrderAt = source.LastOrderAt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
            StoredBalance = source.StoredBalance,
            PointsBalance = source.PointsBalance,
            IsDormant = source.IsDormant
        };
    }

    private static MemberDetailResponse MapDetail(MemberDetailDto source)
    {
        return new MemberDetailResponse
        {
            MemberId = source.MemberId.ToString(),
            Name = source.Name,
            AvatarText = source.AvatarText,
            AvatarColor = source.AvatarColor,
            MobileMasked = source.MobileMasked,
            JoinedAt = source.JoinedAt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
            TierId = source.TierId?.ToString(),
            TierName = source.TierName,
            TierColorHex = source.TierColorHex,
            TotalAmount = source.TotalAmount,
            OrderCount = source.OrderCount,
            AverageAmount = source.AverageAmount,
            StoredBalance = source.StoredBalance,
            StoredRechargeBalance = source.StoredRechargeBalance,
            StoredGiftBalance = source.StoredGiftBalance,
            PointsBalance = source.PointsBalance,
            Tags = source.Tags.ToList(),
            RecentOrders = source.RecentOrders.Select(item => new MemberRecentOrderResponse
            {
                OrderedAt = item.OrderedAt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
                OrderNo = item.OrderNo,
                Amount = item.Amount,
                StatusText = item.StatusText
            }).ToList()
        };
    }
}
