using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.Bag;
using QYZH.InteractiveMagazine.Models.Dto.Mall;
using QYZH.InteractiveMagazine.Models.Dto.Points;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Repository;
using System.Text.Json;

namespace QYZH.InteractiveMagazine.Service;

/// <summary>
/// 小程序商城服务实现
/// </summary>
public class WxMallService(
    BaseRepository<ExchangeRecord> exchangeRecordRepository,
    ICheckInService checkInService,
    IPointsService pointsService,
    ILogger<WxMallService> logger)
    : BaseRepository<ExchangeRecord>, IWxMallService
{
    /// <summary>
    /// 从 MetaData JSON 中提取 SkinId
    /// </summary>
    private static long GetSkinIdFromMetaData(string? metaData)
    {
        if (string.IsNullOrWhiteSpace(metaData)) return 0;
        try
        {
            using var doc = JsonDocument.Parse(metaData);
            if (doc.RootElement.TryGetProperty("SkinId", out var skinIdElement))
                return skinIdElement.GetInt64();
            if (doc.RootElement.TryGetProperty("skinId", out var skinIdLower))
                return skinIdLower.GetInt64();
        }
        catch { }
        return 0;
    }

    /// <summary>
    /// 获取商城商品列表（仅上架 + 在售）
    /// </summary>
    public async Task<List<WxProductOutput>> GetProductsAsync(long userId, string? type = null)
    {
        var query = exchangeRecordRepository.Context.Queryable<Product>()
            .Where(p => !p.IsDeleted && p.IsActive && p.Status == (int)ProductStatusEnum.OnSale)
            .WhereIF(!string.IsNullOrEmpty(type), p => p.Type.ToString() == type)
            .OrderByDescending(p => p.CreatedAt);

        var products = await query.ToListAsync();

        // 批量提取 PetBg 商品的 SkinId
        var skinProductMap = products
            .Where(p => p.Type == ProductTypeEnum.PetSkin)
            .Select(p => new { ProductId = p.Id, SkinId = GetSkinIdFromMetaData(p.MetaData) })
            .Where(x => x.SkinId > 0)
            .ToList();

        var skinIds = skinProductMap.Select(x => x.SkinId).Distinct().ToList();

        // 批量查询皮肤
        var skins = skinIds.Count > 0
            ? await exchangeRecordRepository.Context.Queryable<PetSkin>()
                .Where(s => skinIds.Contains(s.Id) && !s.IsDeleted)
                .ToListAsync()
            : new List<PetSkin>();

        // 批量查询皮肤预览图（取每个皮肤的第一张图）
        var allPreviewImages = skinIds.Count > 0
            ? await exchangeRecordRepository.Context.Queryable<PetSkinImage>()
                .Where(i => skinIds.Contains(i.SkinId) && !i.IsDeleted)
                .OrderBy(i => i.SortOrder)
                .ToListAsync()
            : new List<PetSkinImage>();

        var previewImageMap = allPreviewImages
            .GroupBy(i => i.SkinId)
            .ToDictionary(g => g.Key, g => g.First().ImageUrl);

        // 批量查询用户背包（判断已拥有）
        var skinProductIds = skinProductMap.Select(x => x.ProductId).ToList();
        var bagItems = skinProductIds.Count > 0
            ? await exchangeRecordRepository.Context.Queryable<UserBag>()
                .Where(b => b.UserId == userId && !b.IsDeleted && b.Status == (int)UserBagStatusEnum.Available
                            && skinProductIds.Contains(b.ItemId))
                .ToListAsync()
            : new List<UserBag>();

        return products.Select(p =>
        {
            var skinMapping = skinProductMap.FirstOrDefault(x => x.ProductId == p.Id);
            var skin = skinMapping != null ? skins.FirstOrDefault(s => s.Id == skinMapping.SkinId) : null;
            var owned = bagItems.Any(b => b.ItemId == p.Id);
            var previewImg = skin != null && previewImageMap.ContainsKey(skin.Id) ? previewImageMap[skin.Id] : null;

            return new WxProductOutput
            {
                Id = p.Id,
                Name = p.Name,
                Description = p.Description,
                ImageUrl = p.ImageUrl,
                Price = p.Price,
                Type = p.Type.ToString(),
                IsVirtual = p.IsVirtual,
                TypeId = p.TypeId,
                Owned = owned,
                Skin = skin != null ? new PetSkinBrief
                {
                    SkinId = skin.Id,
                    SkinName = skin.Name,
                    Description = skin.Description,
                    Rarity = skin.Rarity,
                    PreviewImage = previewImg
                } : null
            };
        }).ToList();
    }

    /// <summary>
    /// 获取商品详情
    /// </summary>
    public async Task<WxProductOutput?> GetProductDetailAsync(long userId, long productId)
    {
        var product = await exchangeRecordRepository.Context.Queryable<Product>()
            .Where(p => p.Id == productId && !p.IsDeleted && p.IsActive && p.Status == (int)ProductStatusEnum.OnSale)
            .FirstAsync();

        if (product == null) return null;

        PetSkinBrief? skinBrief = null;
        if (product.Type == ProductTypeEnum.PetSkin)
        {
            var skinId = GetSkinIdFromMetaData(product.MetaData);
            if (skinId > 0)
            {
                var skin = await exchangeRecordRepository.Context.Queryable<PetSkin>()
                    .Where(s => s.Id == skinId && !s.IsDeleted)
                    .FirstAsync();

                if (skin != null)
                {
                    var previewImg = await exchangeRecordRepository.Context.Queryable<PetSkinImage>()
                        .Where(i => i.SkinId == skinId && !i.IsDeleted)
                        .OrderBy(i => i.SortOrder)
                        .Select(i => i.ImageUrl)
                        .FirstAsync();

                    skinBrief = new PetSkinBrief
                    {
                        SkinId = skin.Id,
                        SkinName = skin.Name,
                        Description = skin.Description,
                        Rarity = skin.Rarity,
                        PreviewImage = previewImg
                    };
                }
            }
        }

        var owned = await exchangeRecordRepository.Context.Queryable<UserBag>()
            .Where(b => b.UserId == userId && b.ItemId == product.Id && !b.IsDeleted && b.Status == (int)UserBagStatusEnum.Available)
            .AnyAsync();

        return new WxProductOutput
        {
            Id = product.Id,
            Name = product.Name,
            Description = product.Description,
            ImageUrl = product.ImageUrl,
            Price = product.Price,
            Type = product.Type.ToString(),
            IsVirtual = product.IsVirtual,
            TypeId = product.TypeId,
            Owned = owned,
            Skin = skinBrief
        };
    }

    /// <summary>
    /// 积分兑换商品
    /// </summary>
    public async Task<ExchangeOutput> ExchangeAsync(long userId, ExchangeInput input)
    {
        logger.LogInformation("用户兑换商品，UserId: {UserId}, ProductId: {ProductId}, Qty: {Qty}",
            userId, input.ProductId, input.Quantity);

        if (input.ProductId <= 0)
            throw new BusinessException("商品Id无效", ResultCode.BAD_REQUEST);

        if (input.Quantity <= 0)
            throw new BusinessException("兑换数量必须大于0", ResultCode.BAD_REQUEST);

        // 查询商品
        var product = await exchangeRecordRepository.Context.Queryable<Product>()
            .Where(p => p.Id == input.ProductId && !p.IsDeleted && p.IsActive && p.Status == (int)ProductStatusEnum.OnSale)
            .FirstAsync();

        if (product == null)
            throw new BusinessException("商品不存在或已下架", ResultCode.NOT_FOUND);

        var totalCost = product.Price * input.Quantity;

        DeductPointsOutput? pointsResult = null;
        long recordId = 0;

        await exchangeRecordRepository.UseTranAsync(async () =>
        {
            // 创建兑换记录
            var record = new ExchangeRecord
            {
                UserId = userId,
                ProductId = product.Id,
                ProductName = product.Name,
                ProductType = product.Type.ToString(),
                PointsCost = totalCost,
                PointsBalance = 0, // 稍后赋值
                Quantity = input.Quantity,
                Status = (int)ExchangeRecordStatusEnum.Success,
                IsDeleted = false,
                CreatedBy = userId.ToString(),
                CreatedAt = DateTime.Now,
                UpdatedBy = userId.ToString(),
                UpdatedAt = DateTime.Now
            };
            var inserted = await exchangeRecordRepository.InsertReturnEntityAsync(record);
            recordId = inserted.Id;

            // 扣除积分
            pointsResult = await pointsService.DeductPointsInTranAsync(new DeductPointsInput
            {
                UserId = userId,
                Amount = totalCost,
                ChangeType = PointsChangeTypeEnum.Exchange,
                RelatedId = recordId,
                Description = $"兑换 {product.Name} x{input.Quantity}"
            });

            // 更新兑换记录的积分余额
            await exchangeRecordRepository.Updateable<ExchangeRecord>()
                .SetColumns(r => r.PointsBalance == pointsResult.NewBalance)
                .Where(r => r.Id == recordId)
                .ExecuteCommandAsync();

            // 加入背包
            var existingBag = await exchangeRecordRepository.Context.Queryable<UserBag>()
                .Where(b => b.UserId == userId && b.ItemId == product.Id && !b.IsDeleted && b.Status == (int)UserBagStatusEnum.Available)
                .FirstAsync();

            if (existingBag != null)
            {
                // 已有同类物品，累加数量
                await exchangeRecordRepository.Context.Updateable<UserBag>()
                    .SetColumns(b => b.Quantity == existingBag.Quantity + input.Quantity)
                    .SetColumns(b => b.UpdatedAt == DateTime.Now)
                    .Where(b => b.Id == existingBag.Id)
                    .ExecuteCommandAsync();
            }
            else
            {
                // 新建背包物品
                var bagItem = new UserBag
                {
                    UserId = userId,
                    ItemId = product.Id,
                    ItemType = product.Type.ToString(),
                    Quantity = input.Quantity,
                    MetaData = product.MetaData,
                    Type = Enum.TryParse<UserBagTypeEnum>(product.Type.ToString(), out var bagType) ? bagType : default,
                    Status = (int)UserBagStatusEnum.Available,
                    IsDeleted = false,
                    CreatedBy = userId.ToString(),
                    CreatedAt = DateTime.Now,
                    UpdatedBy = userId.ToString(),
                    UpdatedAt = DateTime.Now
                };
                await exchangeRecordRepository.Context.Insertable(bagItem).ExecuteCommandAsync();
            }
        });

        logger.LogInformation("兑换成功，UserId: {UserId}, Product: {Product}, Cost: {Cost}",
            userId, product.Name, totalCost);

        return new ExchangeOutput
        {
            RecordId = recordId,
            ProductName = product.Name,
            PointsCost = totalCost,
            PointsBalance = pointsResult!.NewBalance,
            Message = $"兑换成功！{product.Name} x{input.Quantity} 已放入背包"
        };
    }

    /// <summary>
    /// 获取用户兑换记录
    /// </summary>
    public async Task<List<ExchangeRecordOutput>> GetExchangeRecordsAsync(long userId, int limit = 20)
    {
        return await exchangeRecordRepository.Queryable()
            .Where(r => r.UserId == userId && !r.IsDeleted)
            .OrderByDescending(r => r.CreatedAt)
            .Take(limit)
            .Select(r => new ExchangeRecordOutput
            {
                Id = r.Id,
                ProductId = r.ProductId,
                ProductName = r.ProductName,
                ProductType = r.ProductType,
                PointsCost = r.PointsCost,
                PointsBalance = r.PointsBalance,
                Quantity = r.Quantity,
                Status = r.Status.ToString(),
                CreatedAt = r.CreatedAt
            })
            .ToListAsync();
    }

    /// <summary>
    /// 获取用户背包物品
    /// </summary>
    public async Task<List<UserBagOutput>> GetBagItemsAsync(long userId, string? itemType = null)
    {
        var query = exchangeRecordRepository.Context.Queryable<UserBag>()
            .Where(b => b.UserId == userId && !b.IsDeleted && b.Status == (int)UserBagStatusEnum.Available)
            .WhereIF(!string.IsNullOrEmpty(itemType), b => b.ItemType == itemType)
            .OrderByDescending(b => b.CreatedAt);

        var bagItems = await query.ToListAsync();

        if (bagItems.Count == 0) return [];

        // 批量查询关联商品
        var itemIds = bagItems.Select(b => b.ItemId).Distinct().ToList();
        var products = await exchangeRecordRepository.Context.Queryable<Product>()
            .Where(p => itemIds.Contains(p.Id) && !p.IsDeleted)
            .ToListAsync();

        // 批量提取 PetBg 背包物品的 SkinId（从 MetaData 解析）
        var skinIdMap = bagItems
            .Where(b => b.ItemType == "PetBg")
            .Select(b => new { BagId = b.Id, SkinId = GetSkinIdFromMetaData(b.MetaData) })
            .Where(x => x.SkinId > 0)
            .ToList();

        var skinIds = skinIdMap.Select(x => x.SkinId).Distinct().ToList();

        // 批量查询皮肤
        var skins = skinIds.Count > 0
            ? await exchangeRecordRepository.Context.Queryable<PetSkin>()
                .Where(s => skinIds.Contains(s.Id) && !s.IsDeleted)
                .ToListAsync()
            : new List<PetSkin>();

        // 批量查询皮肤预览图
        var allBagPreviewImages = skinIds.Count > 0
            ? await exchangeRecordRepository.Context.Queryable<PetSkinImage>()
                .Where(i => skinIds.Contains(i.SkinId) && !i.IsDeleted)
                .OrderBy(i => i.SortOrder)
                .ToListAsync()
            : new List<PetSkinImage>();

        var bagPreviewImageMap = allBagPreviewImages
            .GroupBy(i => i.SkinId)
            .ToDictionary(g => g.Key, g => g.First().ImageUrl);

        return bagItems.Select(b =>
        {
            var product = products.FirstOrDefault(p => p.Id == b.ItemId);
            var skinMapping = skinIdMap.FirstOrDefault(x => x.BagId == b.Id);
            var skin = skinMapping != null ? skins.FirstOrDefault(s => s.Id == skinMapping.SkinId) : null;
            var previewImg = skin != null && bagPreviewImageMap.ContainsKey(skin.Id) ? bagPreviewImageMap[skin.Id] : null;

            return new UserBagOutput
            {
                Id = b.Id,
                ItemId = b.ItemId,
                ItemType = b.ItemType,
                Quantity = b.Quantity,
                Status = b.Status.ToString(),
                CreatedAt = b.CreatedAt,
                Product = product != null ? new BagProductBrief
                {
                    Name = product.Name,
                    ImageUrl = product.ImageUrl,
                    Description = product.Description
                } : null,
                Skin = skin != null ? new BagSkinBrief
                {
                    SkinId = skin.Id,
                    SkinName = skin.Name,
                    Rarity = skin.Rarity,
                    PreviewImage = previewImg
                } : null
            };
        }).ToList();
    }

    /// <summary>
    /// 使用背包物品（目前仅支持补签卡）
    /// </summary>
    public async Task<UseItemOutput> UseItemAsync(long userId, UseItemInput input)
    {
        logger.LogInformation("使用背包物品，UserId: {UserId}, BagItemId: {BagItemId}", userId, input.BagItemId);

        if (input.BagItemId <= 0)
            throw new BusinessException("背包物品Id无效", ResultCode.BAD_REQUEST);

        var bagItem = await exchangeRecordRepository.Context.Queryable<UserBag>()
            .Where(b => b.Id == input.BagItemId && b.UserId == userId && b.Status == (int)UserBagStatusEnum.Available)
            .FirstAsync();

        if (bagItem == null)
            throw new BusinessException("背包物品不存在", ResultCode.NOT_FOUND);

        if (bagItem.Quantity <= 0)
            throw new BusinessException("物品数量不足", ResultCode.BAD_REQUEST);

        switch (bagItem.ItemType)
        {
            case "MakeUpCard":
                return await UseMakeUpCardAsync(userId, bagItem, input);
            default:
                throw new BusinessException($"不支持使用该类型物品: {bagItem.ItemType}", ResultCode.BAD_REQUEST);
        }
    }

    /// <summary>
    /// 使用补签卡
    /// </summary>
    private async Task<UseItemOutput> UseMakeUpCardAsync(long userId, UserBag bagItem, UseItemInput input)
    {
        if (string.IsNullOrEmpty(input.TargetDate))
            throw new BusinessException("请指定补签日期", ResultCode.BAD_REQUEST);

        if (!DateTime.TryParse(input.TargetDate, out var targetDate))
            throw new BusinessException("日期格式无效", ResultCode.BAD_REQUEST);

        targetDate = targetDate.Date;

        if (targetDate >= DateTime.Now.Date)
            throw new BusinessException("只能补签过去的日期", ResultCode.BAD_REQUEST);

        // 调用签到服务执行补签（内部会检查并扣减补签卡）
        var checkInResult = await checkInService.MakeUpCheckInAsync(userId, targetDate);

        logger.LogInformation("补签卡使用成功，UserId: {UserId}, TargetDate: {Date}", userId, targetDate);

        return new UseItemOutput
        {
            IsSuccess = true,
            Message = $"补签 {targetDate:yyyy-MM-dd} 成功",
            Extra = checkInResult
        };
    }

    /// <summary>
    /// 宠物换肤
    /// </summary>
    public async Task EquipSkinAsync(long userId, EquipSkinInput input)
    {
        logger.LogInformation("宠物换肤，UserId: {UserId}, SkinId: {SkinId}", userId, input.SkinId);

        // 查询用户宠物
        var pet = await exchangeRecordRepository.Context.Queryable<UserPet>()
            .Where(p => p.UserId == userId && !p.IsDeleted)
            .FirstAsync();

        if (pet == null)
            throw new BusinessException("您还没有宠物", ResultCode.NOT_FOUND);

        if (input.SkinId == 0)
        {
            // 恢复默认皮肤
            await exchangeRecordRepository.Context.Updateable<UserPet>()
                .SetColumns(p => p.CurrentSkinId == 0)
                .SetColumns(p => p.UpdatedAt == DateTime.Now)
                .Where(p => p.Id == pet.Id)
                .ExecuteCommandAsync();

            logger.LogInformation("宠物恢复默认皮肤，UserId: {UserId}", userId);
            return;
        }

        // 查询皮肤
        var skin = await exchangeRecordRepository.Context.Queryable<PetSkin>()
            .Where(s => s.Id == input.SkinId && !s.IsDeleted)
            .FirstAsync();

        if (skin == null)
            throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);

        // 校验背包中是否拥有该皮肤（通过 MetaData 中的 SkinId 判断）
        var hasSkin = await exchangeRecordRepository.Context.Queryable<UserBag>()
            .Where(b => b.UserId == userId && !b.IsDeleted && b.Status == (int)UserBagStatusEnum.Available && b.Quantity > 0
                        && b.ItemType == "PetBg")
            .ToListAsync();

        var owned = hasSkin.Any(b => GetSkinIdFromMetaData(b.MetaData) == input.SkinId);

        if (!owned)
            throw new BusinessException("您尚未拥有该皮肤，请先兑换", ResultCode.BAD_REQUEST);

        // 换肤
        await exchangeRecordRepository.Context.Updateable<UserPet>()
            .SetColumns(p => p.CurrentSkinId == skin.Id)
            .SetColumns(p => p.UpdatedAt == DateTime.Now)
            .Where(p => p.Id == pet.Id)
            .ExecuteCommandAsync();

        logger.LogInformation("宠物换肤成功，UserId: {UserId}, Skin: {Skin}", userId, skin.Name);
    }
}
