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/tier")]
public sealed class MemberTierController(
    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<List<MemberTierListItemResponse>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<List<MemberTierListItemResponse>>> List(CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new GetMemberTierListQuery(), cancellationToken);
        return ApiResponse<List<MemberTierListItemResponse>>.Ok(result.Select(MapTierListItem).ToList());
    }

    /// <summary>
    /// 获取会员等级详情。
    /// </summary>
    [HttpGet("detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberTierDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberTierDetailResponse>> Detail(
        [FromQuery] MemberTierDetailRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new GetMemberTierDetailQuery
        {
            TierId = StoreApiHelpers.ParseSnowflakeOrNull(request.TierId)
        }, cancellationToken);

        return ApiResponse<MemberTierDetailResponse>.Ok(MapTierDetail(result));
    }

    /// <summary>
    /// 保存会员等级。
    /// </summary>
    [HttpPost("save")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberTierDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberTierDetailResponse>> Save(
        [FromBody] SaveMemberTierRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new SaveMemberTierCommand
        {
            TierId = StoreApiHelpers.ParseSnowflakeOrNull(request.TierId),
            SortOrder = request.SortOrder,
            Name = request.Name,
            IconKey = request.IconKey,
            ColorHex = request.ColorHex,
            IsDefault = request.IsDefault,
            Rule = new MemberTierRuleDto
            {
                UpgradeRuleType = request.Rule.UpgradeRuleType,
                UpgradeAmountThreshold = request.Rule.UpgradeAmountThreshold,
                UpgradeOrderCountThreshold = request.Rule.UpgradeOrderCountThreshold,
                DowngradeWindowDays = request.Rule.DowngradeWindowDays
            },
            Benefits = MapBenefits(request.Benefits)
        }, cancellationToken);

        return ApiResponse<MemberTierDetailResponse>.Ok(MapTierDetail(result));
    }

    /// <summary>
    /// 删除会员等级。
    /// </summary>
    [HttpPost("delete")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> Delete(
        [FromBody] DeleteMemberTierRequest request,
        CancellationToken cancellationToken)
    {
        await mediator.Send(new DeleteMemberTierCommand
        {
            TierId = StoreApiHelpers.ParseRequiredSnowflake(request.TierId, nameof(request.TierId))
        }, cancellationToken);

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

    /// <summary>
    /// 获取会员日配置。
    /// </summary>
    [HttpGet("day-setting")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberDaySettingResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberDaySettingResponse>> GetDaySetting(CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new GetMemberDaySettingQuery(), cancellationToken);
        return ApiResponse<MemberDaySettingResponse>.Ok(new MemberDaySettingResponse
        {
            IsEnabled = result.IsEnabled,
            Weekday = result.Weekday,
            ExtraDiscountRate = result.ExtraDiscountRate
        });
    }

    /// <summary>
    /// 保存会员日配置。
    /// </summary>
    [HttpPost("day-setting")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<MemberDaySettingResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<MemberDaySettingResponse>> SaveDaySetting(
        [FromBody] SaveMemberDaySettingRequest request,
        CancellationToken cancellationToken)
    {
        var result = await mediator.Send(new SaveMemberDaySettingCommand
        {
            IsEnabled = request.IsEnabled,
            Weekday = request.Weekday,
            ExtraDiscountRate = request.ExtraDiscountRate
        }, cancellationToken);

        return ApiResponse<MemberDaySettingResponse>.Ok(new MemberDaySettingResponse
        {
            IsEnabled = result.IsEnabled,
            Weekday = result.Weekday,
            ExtraDiscountRate = result.ExtraDiscountRate
        });
    }

    /// <summary>
    /// 查询可选优惠券列表。
    /// </summary>
    [HttpGet("coupon-picker")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<List<MemberCouponPickerItemResponse>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<List<MemberCouponPickerItemResponse>>> CouponPicker(
        [FromQuery] MemberCouponPickerRequest request,
        CancellationToken cancellationToken)
    {
        var visibleStoreIds = await ResolveVisibleStoreIdsAsync(request.StoreId, cancellationToken);

        var result = await mediator.Send(new SearchMemberCouponPickerQuery
        {
            VisibleStoreIds = visibleStoreIds,
            Keyword = request.Keyword
        }, cancellationToken);

        return ApiResponse<List<MemberCouponPickerItemResponse>>.Ok(result.Select(item => new MemberCouponPickerItemResponse
        {
            CouponTemplateId = item.CouponTemplateId.ToString(),
            Name = item.Name,
            CouponType = item.CouponType,
            Value = item.Value,
            MinimumSpend = item.MinimumSpend,
            DisplayText = item.DisplayText
        }).ToList());
    }

    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 MemberTierListItemResponse MapTierListItem(MemberTierListItemDto source)
    {
        return new MemberTierListItemResponse
        {
            TierId = source.TierId.ToString(),
            SortOrder = source.SortOrder,
            Name = source.Name,
            IconKey = source.IconKey,
            ColorHex = source.ColorHex,
            ConditionText = source.ConditionText,
            Perks = source.Perks.ToList(),
            MemberCount = source.MemberCount,
            IsDefault = source.IsDefault,
            CanDelete = source.CanDelete
        };
    }

    private static MemberTierDetailResponse MapTierDetail(MemberTierDetailDto source)
    {
        return new MemberTierDetailResponse
        {
            TierId = source.TierId?.ToString(),
            SortOrder = source.SortOrder,
            Name = source.Name,
            IconKey = source.IconKey,
            ColorHex = source.ColorHex,
            IsDefault = source.IsDefault,
            Rule = new MemberTierRuleResponse
            {
                UpgradeRuleType = source.Rule.UpgradeRuleType,
                UpgradeAmountThreshold = source.Rule.UpgradeAmountThreshold,
                UpgradeOrderCountThreshold = source.Rule.UpgradeOrderCountThreshold,
                DowngradeWindowDays = source.Rule.DowngradeWindowDays
            },
            Benefits = new MemberTierBenefitsResponse
            {
                Discount = new MemberTierDiscountBenefitResponse
                {
                    Enabled = source.Benefits.Discount.Enabled,
                    DiscountRate = source.Benefits.Discount.DiscountRate
                },
                PointMultiplier = new MemberTierPointMultiplierBenefitResponse
                {
                    Enabled = source.Benefits.PointMultiplier.Enabled,
                    Multiplier = source.Benefits.PointMultiplier.Multiplier
                },
                Birthday = new MemberTierBirthdayBenefitResponse
                {
                    Enabled = source.Benefits.Birthday.Enabled,
                    DoublePointsEnabled = source.Benefits.Birthday.DoublePointsEnabled,
                    CouponTemplateIds = source.Benefits.Birthday.CouponTemplateIds.Select(item => item.ToString()).ToList()
                },
                MonthlyCoupon = new MemberTierMonthlyCouponBenefitResponse
                {
                    Enabled = source.Benefits.MonthlyCoupon.Enabled,
                    GrantDay = source.Benefits.MonthlyCoupon.GrantDay,
                    CouponTemplateIds = source.Benefits.MonthlyCoupon.CouponTemplateIds.Select(item => item.ToString()).ToList()
                },
                FreeDelivery = new MemberTierFreeDeliveryBenefitResponse
                {
                    Enabled = source.Benefits.FreeDelivery.Enabled,
                    MonthlyFreeTimes = source.Benefits.FreeDelivery.MonthlyFreeTimes
                },
                PriorityDeliveryEnabled = source.Benefits.PriorityDeliveryEnabled,
                ExclusiveServiceEnabled = source.Benefits.ExclusiveServiceEnabled
            },
            CanDelete = source.CanDelete
        };
    }

    private static MemberTierBenefitsDto MapBenefits(MemberTierBenefitsResponse source)
    {
        return new MemberTierBenefitsDto
        {
            Discount = new MemberTierDiscountBenefitDto
            {
                Enabled = source.Discount.Enabled,
                DiscountRate = source.Discount.DiscountRate
            },
            PointMultiplier = new MemberTierPointMultiplierBenefitDto
            {
                Enabled = source.PointMultiplier.Enabled,
                Multiplier = source.PointMultiplier.Multiplier
            },
            Birthday = new MemberTierBirthdayBenefitDto
            {
                Enabled = source.Birthday.Enabled,
                DoublePointsEnabled = source.Birthday.DoublePointsEnabled,
                CouponTemplateIds = source.Birthday.CouponTemplateIds
                    .Select(StoreApiHelpers.ParseSnowflakeOrNull)
                    .Where(item => item.HasValue)
                    .Select(item => item!.Value)
                    .ToList()
            },
            MonthlyCoupon = new MemberTierMonthlyCouponBenefitDto
            {
                Enabled = source.MonthlyCoupon.Enabled,
                GrantDay = source.MonthlyCoupon.GrantDay,
                CouponTemplateIds = source.MonthlyCoupon.CouponTemplateIds
                    .Select(StoreApiHelpers.ParseSnowflakeOrNull)
                    .Where(item => item.HasValue)
                    .Select(item => item!.Value)
                    .ToList()
            },
            FreeDelivery = new MemberTierFreeDeliveryBenefitDto
            {
                Enabled = source.FreeDelivery.Enabled,
                MonthlyFreeTimes = source.FreeDelivery.MonthlyFreeTimes
            },
            PriorityDeliveryEnabled = source.PriorityDeliveryEnabled,
            ExclusiveServiceEnabled = source.ExclusiveServiceEnabled
        };
    }
}
