using System.Globalization;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.App.Members.PointsMall.Commands;
using TakeoutSaaS.Application.App.Members.PointsMall.Dto;
using TakeoutSaaS.Application.App.Members.PointsMall.Queries;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Infrastructure.App.Persistence;
using TakeoutSaaS.Module.Authorization.Attributes;
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/points-mall")]
public sealed class MemberPointsMallController(
    IMediator mediator,
    TakeoutAppDbContext dbContext,
    StoreContextService storeContextService)
    : BaseApiController
{
    private const string ViewPermission = "tenant:member:points-mall:view";
    private const string ManagePermission = "tenant:member:points-mall:manage";

    /// <summary>
    /// 获取积分规则详情。
    /// </summary>
    [HttpGet("rule/detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRuleDetailResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRuleDetailResultResponse>> RuleDetail(
        [FromQuery] PointMallRuleDetailRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetPointMallRuleDetailQuery
        {
            StoreId = storeId
        }, cancellationToken);

        return ApiResponse<PointMallRuleDetailResultResponse>.Ok(new PointMallRuleDetailResultResponse
        {
            Rule = MapRule(result.Rule),
            Stats = new PointMallRuleStatsResponse
            {
                TotalIssuedPoints = result.Stats.TotalIssuedPoints,
                RedeemedPoints = result.Stats.RedeemedPoints,
                PointMembers = result.Stats.PointMembers,
                RedeemRate = result.Stats.RedeemRate
            }
        });
    }

    /// <summary>
    /// 保存积分规则。
    /// </summary>
    [HttpPost("rule/save")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRuleResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRuleResponse>> SaveRule(
        [FromBody] SavePointMallRuleRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new SavePointMallRuleCommand
        {
            StoreId = storeId,
            IsConsumeRewardEnabled = request.IsConsumeRewardEnabled,
            ConsumeAmountPerStep = request.ConsumeAmountPerStep,
            ConsumeRewardPointsPerStep = request.ConsumeRewardPointsPerStep,
            IsReviewRewardEnabled = request.IsReviewRewardEnabled,
            ReviewRewardPoints = request.ReviewRewardPoints,
            IsRegisterRewardEnabled = request.IsRegisterRewardEnabled,
            RegisterRewardPoints = request.RegisterRewardPoints,
            IsSigninRewardEnabled = request.IsSigninRewardEnabled,
            SigninRewardPoints = request.SigninRewardPoints,
            ExpiryMode = request.ExpiryMode
        }, cancellationToken);

        return ApiResponse<PointMallRuleResponse>.Ok(MapRule(result));
    }

    /// <summary>
    /// 查询兑换商品列表。
    /// </summary>
    [HttpGet("product/list")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallProductListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallProductListResultResponse>> ProductList(
        [FromQuery] PointMallProductListRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetPointMallProductListQuery
        {
            StoreId = storeId,
            Status = request.Status,
            Keyword = request.Keyword
        }, cancellationToken);

        return ApiResponse<PointMallProductListResultResponse>.Ok(new PointMallProductListResultResponse
        {
            Items = result.Items.Select(MapProduct).ToList()
        });
    }

    /// <summary>
    /// 查询兑换商品详情。
    /// </summary>
    [HttpGet("product/detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallProductResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallProductResponse>> ProductDetail(
        [FromQuery] PointMallProductDetailRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetPointMallProductDetailQuery
        {
            StoreId = storeId,
            PointMallProductId = StoreApiHelpers.ParseRequiredSnowflake(request.PointMallProductId, nameof(request.PointMallProductId))
        }, cancellationToken);

        return ApiResponse<PointMallProductResponse>.Ok(MapProduct(result));
    }

    /// <summary>
    /// 保存兑换商品。
    /// </summary>
    [HttpPost("product/save")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallProductResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallProductResponse>> SaveProduct(
        [FromBody] SavePointMallProductRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new SavePointMallProductCommand
        {
            StoreId = storeId,
            PointMallProductId = StoreApiHelpers.ParseSnowflakeOrNull(request.PointMallProductId),
            Name = request.Name,
            ImageUrl = request.ImageUrl,
            RedeemType = request.RedeemType,
            ProductId = StoreApiHelpers.ParseSnowflakeOrNull(request.ProductId),
            CouponTemplateId = StoreApiHelpers.ParseSnowflakeOrNull(request.CouponTemplateId),
            PhysicalName = request.PhysicalName,
            PickupMethod = request.PickupMethod,
            Description = request.Description,
            ExchangeType = request.ExchangeType,
            RequiredPoints = request.RequiredPoints,
            CashAmount = request.CashAmount,
            StockTotal = request.StockTotal,
            PerMemberLimit = request.PerMemberLimit,
            NotifyChannels = request.NotifyChannels,
            Status = request.Status
        }, cancellationToken);

        return ApiResponse<PointMallProductResponse>.Ok(MapProduct(result));
    }

    /// <summary>
    /// 修改兑换商品状态。
    /// </summary>
    [HttpPost("product/status")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallProductResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallProductResponse>> ChangeProductStatus(
        [FromBody] ChangePointMallProductStatusRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new ChangePointMallProductStatusCommand
        {
            StoreId = storeId,
            PointMallProductId = StoreApiHelpers.ParseRequiredSnowflake(request.PointMallProductId, nameof(request.PointMallProductId)),
            Status = request.Status
        }, cancellationToken);

        return ApiResponse<PointMallProductResponse>.Ok(MapProduct(result));
    }

    /// <summary>
    /// 删除兑换商品。
    /// </summary>
    [HttpPost("product/delete")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> DeleteProduct(
        [FromBody] DeletePointMallProductRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        await mediator.Send(new DeletePointMallProductCommand
        {
            StoreId = storeId,
            PointMallProductId = StoreApiHelpers.ParseRequiredSnowflake(request.PointMallProductId, nameof(request.PointMallProductId))
        }, cancellationToken);

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

    /// <summary>
    /// 查询兑换记录分页。
    /// </summary>
    [HttpGet("record/list")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRecordListResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRecordListResultResponse>> RecordList(
        [FromQuery] PointMallRecordListRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetPointMallRecordListQuery
        {
            StoreId = storeId,
            RedeemType = request.RedeemType,
            Status = request.Status,
            StartDateUtc = ParseDateOrNull(request.StartDate, nameof(request.StartDate)),
            EndDateUtc = ParseDateOrNull(request.EndDate, nameof(request.EndDate)),
            Keyword = request.Keyword,
            Page = request.Page,
            PageSize = request.PageSize
        }, cancellationToken);

        return ApiResponse<PointMallRecordListResultResponse>.Ok(new PointMallRecordListResultResponse
        {
            Items = result.Items.Select(MapRecord).ToList(),
            Page = result.Page,
            PageSize = result.PageSize,
            TotalCount = result.TotalCount,
            Stats = new PointMallRecordStatsResponse
            {
                TodayRedeemCount = result.Stats.TodayRedeemCount,
                PendingPhysicalCount = result.Stats.PendingPhysicalCount,
                CurrentMonthUsedPoints = result.Stats.CurrentMonthUsedPoints
            }
        });
    }

    /// <summary>
    /// 查询兑换记录详情。
    /// </summary>
    [HttpGet("record/detail")]
    [PermissionAuthorize(ViewPermission, ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRecordDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRecordDetailResponse>> RecordDetail(
        [FromQuery] PointMallRecordDetailRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetPointMallRecordDetailQuery
        {
            StoreId = storeId,
            RecordId = StoreApiHelpers.ParseRequiredSnowflake(request.RecordId, nameof(request.RecordId))
        }, cancellationToken);

        return ApiResponse<PointMallRecordDetailResponse>.Ok(MapRecordDetail(result));
    }

    /// <summary>
    /// 导出兑换记录 CSV。
    /// </summary>
    [HttpGet("record/export")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRecordExportResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRecordExportResponse>> ExportRecord(
        [FromQuery] ExportPointMallRecordRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new ExportPointMallRecordCsvQuery
        {
            StoreId = storeId,
            RedeemType = request.RedeemType,
            Status = request.Status,
            StartDateUtc = ParseDateOrNull(request.StartDate, nameof(request.StartDate)),
            EndDateUtc = ParseDateOrNull(request.EndDate, nameof(request.EndDate)),
            Keyword = request.Keyword
        }, cancellationToken);

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

    /// <summary>
    /// 写入兑换记录。
    /// </summary>
    [HttpPost("record/write")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRecordResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRecordResponse>> WriteRecord(
        [FromBody] WritePointMallRecordRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new WritePointMallRecordCommand
        {
            StoreId = storeId,
            PointMallProductId = StoreApiHelpers.ParseRequiredSnowflake(request.PointMallProductId, nameof(request.PointMallProductId)),
            MemberId = StoreApiHelpers.ParseRequiredSnowflake(request.MemberId, nameof(request.MemberId)),
            RedeemedAt = request.RedeemedAt
        }, cancellationToken);

        return ApiResponse<PointMallRecordResponse>.Ok(MapRecord(result));
    }

    /// <summary>
    /// 核销兑换记录。
    /// </summary>
    [HttpPost("record/verify")]
    [PermissionAuthorize(ManagePermission)]
    [ProducesResponseType(typeof(ApiResponse<PointMallRecordDetailResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<PointMallRecordDetailResponse>> VerifyRecord(
        [FromBody] VerifyPointMallRecordRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new VerifyPointMallRecordCommand
        {
            StoreId = storeId,
            RecordId = StoreApiHelpers.ParseRequiredSnowflake(request.RecordId, nameof(request.RecordId)),
            VerifyMethod = request.VerifyMethod,
            VerifyRemark = request.VerifyRemark
        }, cancellationToken);

        return ApiResponse<PointMallRecordDetailResponse>.Ok(MapRecordDetail(result));
    }

    private async Task EnsureStoreAccessibleAsync(long storeId, CancellationToken cancellationToken)
    {
        var (tenantId, merchantId) = StoreApiHelpers.GetTenantMerchantContext(storeContextService);
        await StoreApiHelpers.EnsureStoreAccessibleAsync(dbContext, tenantId, merchantId, storeId, cancellationToken);
    }

    private static DateTime? ParseDateOrNull(string? value, string fieldName)
    {
        return string.IsNullOrWhiteSpace(value)
            ? null
            : StoreApiHelpers.ParseDateOnly(value, fieldName);
    }

    private static PointMallRuleResponse MapRule(MemberPointMallRuleDto source)
    {
        return new PointMallRuleResponse
        {
            StoreId = source.StoreId.ToString(),
            IsConsumeRewardEnabled = source.IsConsumeRewardEnabled,
            ConsumeAmountPerStep = source.ConsumeAmountPerStep,
            ConsumeRewardPointsPerStep = source.ConsumeRewardPointsPerStep,
            IsReviewRewardEnabled = source.IsReviewRewardEnabled,
            ReviewRewardPoints = source.ReviewRewardPoints,
            IsRegisterRewardEnabled = source.IsRegisterRewardEnabled,
            RegisterRewardPoints = source.RegisterRewardPoints,
            IsSigninRewardEnabled = source.IsSigninRewardEnabled,
            SigninRewardPoints = source.SigninRewardPoints,
            ExpiryMode = source.ExpiryMode
        };
    }

    private static PointMallProductResponse MapProduct(MemberPointMallProductDto source)
    {
        return new PointMallProductResponse
        {
            PointMallProductId = source.PointMallProductId.ToString(),
            StoreId = source.StoreId.ToString(),
            Name = source.Name,
            ImageUrl = source.ImageUrl,
            RedeemType = source.RedeemType,
            RedeemTypeText = ResolveRedeemTypeText(source.RedeemType),
            ProductId = source.ProductId?.ToString(),
            CouponTemplateId = source.CouponTemplateId?.ToString(),
            PhysicalName = source.PhysicalName,
            PickupMethod = source.PickupMethod,
            Description = source.Description,
            ExchangeType = source.ExchangeType,
            RequiredPoints = source.RequiredPoints,
            CashAmount = source.CashAmount,
            StockTotal = source.StockTotal,
            StockAvailable = source.StockAvailable,
            RedeemedCount = source.RedeemedCount,
            PerMemberLimit = source.PerMemberLimit,
            NotifyChannels = source.NotifyChannels.ToList(),
            Status = source.Status,
            StatusText = ResolveProductStatusText(source.Status),
            UpdatedAt = source.UpdatedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
        };
    }

    private static PointMallRecordResponse MapRecord(MemberPointMallRecordDto source)
    {
        return new PointMallRecordResponse
        {
            RecordId = source.RecordId.ToString(),
            RecordNo = source.RecordNo,
            PointMallProductId = source.PointMallProductId.ToString(),
            ProductName = source.ProductName,
            RedeemType = source.RedeemType,
            RedeemTypeText = ResolveRedeemTypeText(source.RedeemType),
            ExchangeType = source.ExchangeType,
            MemberId = source.MemberId.ToString(),
            MemberName = source.MemberName,
            MemberMobileMasked = source.MemberMobileMasked,
            UsedPoints = source.UsedPoints,
            CashAmount = source.CashAmount,
            Status = source.Status,
            StatusText = ResolveRecordStatusText(source.Status),
            RedeemedAt = source.RedeemedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            IssuedAt = source.IssuedAt?.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            VerifiedAt = source.VerifiedAt?.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
        };
    }

    private static PointMallRecordDetailResponse MapRecordDetail(MemberPointMallRecordDetailDto source)
    {
        var response = new PointMallRecordDetailResponse
        {
            RecordId = source.RecordId.ToString(),
            RecordNo = source.RecordNo,
            PointMallProductId = source.PointMallProductId.ToString(),
            ProductName = source.ProductName,
            RedeemType = source.RedeemType,
            RedeemTypeText = ResolveRedeemTypeText(source.RedeemType),
            ExchangeType = source.ExchangeType,
            MemberId = source.MemberId.ToString(),
            MemberName = source.MemberName,
            MemberMobileMasked = source.MemberMobileMasked,
            UsedPoints = source.UsedPoints,
            CashAmount = source.CashAmount,
            Status = source.Status,
            StatusText = ResolveRecordStatusText(source.Status),
            RedeemedAt = source.RedeemedAt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            IssuedAt = source.IssuedAt?.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            VerifiedAt = source.VerifiedAt?.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
            VerifyMethod = source.VerifyMethod,
            VerifyMethodText = ResolveVerifyMethodText(source.VerifyMethod),
            VerifyRemark = source.VerifyRemark,
            VerifiedBy = source.VerifiedBy?.ToString()
        };

        return response;
    }

    private static string ResolveRedeemTypeText(string value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "product" => "商品",
            "coupon" => "优惠券",
            "physical" => "实物",
            _ => "未知"
        };
    }

    private static string ResolveProductStatusText(string value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "enabled" => "上架",
            "disabled" => "下架",
            _ => "未知"
        };
    }

    private static string ResolveRecordStatusText(string value)
    {
        return (value ?? string.Empty).Trim().ToLowerInvariant() switch
        {
            "pending_pickup" => "待领取",
            "issued" => "已发放",
            "completed" => "已完成",
            "canceled" => "已取消",
            _ => "未知"
        };
    }

    private static string? ResolveVerifyMethodText(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return null;
        }

        return value.Trim().ToLowerInvariant() switch
        {
            "scan" => "扫码核销",
            "manual" => "手动核销",
            _ => "未知"
        };
    }
}
