using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Equity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 权益服务实现
/// </summary>
public class QuanYiService : IQuanYiService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<QuanYiService> _logger;
    private readonly string _imageBaseUrl;

    public QuanYiService(HoneyBoxDbContext dbContext, ILogger<QuanYiService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
        _imageBaseUrl = "https://example.com"; // TODO: Configure from appsettings
    }

    /// <inheritdoc/>
    public async Task<QuanYiResponse> GetQuanYiAsync(int userId)
    {
        var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
        if (user == null)
        {
            throw new InvalidOperationException("用户不存在");
        }

        // 从数据库获取等级配置
        var equityLevelConfigs = await _dbContext.EquityLevels
            .Where(v => v.DeletedAt == null)
            .OrderBy(v => v.Level)
            .ToListAsync();

        var response = new QuanYiResponse
        {
            UserImg = GetImageUrl(user.HeadImg),
            QuanYiLevel = GetQuanYiLevelInfo(user.OuQiLevel ?? 0, user.OuQi ?? 0, equityLevelConfigs)
        };

        // Get all equity levels with level > 0
        var equityLevels = await _dbContext.EquityLevels
            .Where(v => v.Level > 0 && v.DeletedAt == null)
            .OrderBy(v => v.Level)
            .ToListAsync();

        var levelList = new List<QuanYiLevelDto>();

        foreach (var equityLevel in equityLevels)
        {
            var levelDto = new QuanYiLevelDto
            {
                Id = equityLevel.Id,
                Level = equityLevel.Level
            };

            // Get coupon rewards (type = 1)
            var puJiang = await _dbContext.EquityLevelRewards
                .Where(r => r.EquityLevelId == equityLevel.Id && r.Type == 1 && r.DeletedAt == null)
                .OrderBy(r => r.Id)
                .Select(r => new QuanYiRewardDto
                {
                    Id = r.Id,
                    Title = r.Title,
                    ZNum = r.ZNum,
                    ImgUrl = r.ImgUrl
                })
                .ToListAsync();
            levelDto.PuJiang = puJiang;

            // Get prize rewards (type = 2)
            var gaoJiangRaw = await _dbContext.EquityLevelRewards
                .Where(r => r.EquityLevelId == equityLevel.Id && r.Type == 2 && r.DeletedAt == null)
                .OrderBy(r => r.Id)
                .Select(r => new QuanYiRewardDto
                {
                    Id = r.Id,
                    Title = r.Title,
                    ZNum = r.ZNum,
                    ImgUrl = r.ImgUrl
                })
                .ToListAsync();
            // Process image URLs after query
            foreach (var item in gaoJiangRaw)
            {
                item.ImgUrl = GetImageUrl(item.ImgUrl);
            }
            levelDto.GaoJiang = gaoJiangRaw;

            // Check if user can claim this level's rewards
            if ((user.OuQiLevel ?? 0) >= equityLevel.Level)
            {
                levelDto.IsLing = 1; // Can claim
            }
            else
            {
                levelDto.IsLing = 0; // Cannot claim
            }

            // Check if user has already claimed this level's rewards
            var hasClaimed = await _dbContext.UserEquityRewards
                .AnyAsync(r => r.EquityLevelId == equityLevel.Id 
                    && r.EquityLevel == equityLevel.Level 
                    && r.UserId == userId 
                    && r.DeletedAt == null);
            
            if (hasClaimed)
            {
                levelDto.IsLing = 2; // Already claimed
            }

            levelList.Add(levelDto);
        }

        response.LevelList = levelList;

        // Get danye content (ids 1 and 2)
        var danyeList = await _dbContext.Danyes
            .Where(d => d.Id == 1 || d.Id == 2)
            .Select(d => new DanyeDto
            {
                Id = d.Id,
                Title = d.Title,
                Content = d.Content
            })
            .ToListAsync();
        response.DanyeList = danyeList;

        return response;
    }

    /// <inheritdoc/>
    public async Task<QuanYiLingResponse> ClaimQuanYiAsync(int userId, int levelId)
    {
        var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
        if (user == null)
        {
            throw new InvalidOperationException("用户不存在");
        }

        var equityLevel = await _dbContext.EquityLevels
            .FirstOrDefaultAsync(v => v.Id == levelId && v.DeletedAt == null);
        if (equityLevel == null)
        {
            throw new InvalidOperationException("数据错误");
        }

        if (equityLevel.Level > (user.OuQiLevel ?? 0))
        {
            throw new InvalidOperationException("暂未达到该等级");
        }

        // Check if rewards exist for this level
        var hasRewards = await _dbContext.EquityLevelRewards
            .AnyAsync(r => r.EquityLevelId == equityLevel.Id && r.DeletedAt == null);
        if (!hasRewards)
        {
            throw new InvalidOperationException("奖品不存在");
        }

        // Note: PHP code allows re-claiming, so we don't check for existing claims

        var rewards = new List<QuanYiLingRewardDto>();

        using var transaction = await _dbContext.Database.BeginTransactionAsync();
        try
        {
            // Process coupon rewards (type = 1)
            var couponRewards = await _dbContext.EquityLevelRewards
                .Where(r => r.EquityLevelId == equityLevel.Id && r.Type == 1 && r.DeletedAt == null)
                .ToListAsync();

            foreach (var reward in couponRewards)
            {
                var endTime = DateTime.UtcNow.AddDays(reward.EffectiveDay ?? 7);
                
                // 获取关联的优惠券信息
                Coupon? coupon = null;
                if (reward.CouponId.HasValue)
                {
                    coupon = await _dbContext.Coupons
                        .FirstOrDefaultAsync(c => c.Id == reward.CouponId.Value);
                }

                // 优先使用优惠券表的数据，如果没有则使用奖品表的数据
                var jianPrice = coupon?.Price ?? reward.JianPrice ?? 0;
                var manPrice = coupon?.ManPrice ?? reward.ManPrice ?? 0;
                var couponTitle = coupon?.Title ?? reward.Title ?? "优惠券";
                var ttype = coupon?.Ttype ?? 0;

                // Add to response
                rewards.Add(new QuanYiLingRewardDto
                {
                    Id = reward.Id,
                    Title = couponTitle,
                    Type = 1,
                    JianPrice = jianPrice,
                    ManPrice = manPrice,
                    EffectiveDay = reward.EffectiveDay,
                    EndTime = endTime.ToString("yyyy-MM-dd HH:mm:ss"),
                    ZNum = reward.ZNum
                });

                // Create coupon receives for the user
                var zNum = reward.ZNum ?? 1;
                for (int i = 0; i < zNum; i++)
                {
                    var couponReceive = new CouponReceife
                    {
                        UserId = userId,
                        Title = couponTitle,
                        Price = jianPrice,
                        ManPrice = manPrice,
                        EndTime = endTime,
                        CreatedAt = DateTime.UtcNow,
                        CouponId = reward.CouponId ?? reward.Id,
                        State = 0,  // State字段未使用
                        Status = 0, // 0=未使用/可用, 1=已使用, 2=已过期
                        Ttype = ttype
                    };
                    _dbContext.CouponReceives.Add(couponReceive);
                }

                // Record user equity reward
                var userEquityReward = new UserEquityReward
                {
                    UserId = userId,
                    EquityLevelId = equityLevel.Id,
                    EquityLevel = equityLevel.Level,
                    CouponId = reward.CouponId,
                    Type = 1,
                    Title = couponTitle,
                    JianPrice = jianPrice,
                    ManPrice = manPrice,
                    EffectiveDay = reward.EffectiveDay,
                    EndTime = endTime,
                    ZNum = reward.ZNum,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };
                _dbContext.UserEquityRewards.Add(userEquityReward);
            }

            // Process prize rewards (type = 2) with probability
            var prizeRewards = await _dbContext.EquityLevelRewards
                .Where(r => r.EquityLevelId == equityLevel.Id && r.Type == 2 && r.Probability > 0 && r.DeletedAt == null)
                .ToListAsync();

            if (prizeRewards.Any())
            {
                // Build probability pool
                var probabilityPool = new List<EquityLevelReward>();
                foreach (var prize in prizeRewards)
                {
                    var count = (int)((prize.Probability ?? 0) * 100);
                    for (int i = 0; i < count; i++)
                    {
                        probabilityPool.Add(prize);
                    }
                }

                if (probabilityPool.Any())
                {
                    // Shuffle and pick one
                    var random = new Random();
                    var shuffled = probabilityPool.OrderBy(x => random.Next()).ToList();
                    var selectedPrize = shuffled[random.Next(shuffled.Count)];

                    // Add to response
                    rewards.Add(new QuanYiLingRewardDto
                    {
                        Id = selectedPrize.Id,
                        Title = selectedPrize.Title,
                        Type = 2,
                        ImgUrl = GetImageUrl(selectedPrize.ImgUrl),
                        ShangId = selectedPrize.PrizeLevelId
                    });

                    // Create order for the prize
                    var orderNum = GenerateOrderNo("MH_");
                    var order = new Order
                    {
                        UserId = userId,
                        OrderNum = orderNum,
                        OrderTotal = 0,
                        OrderZheTotal = 0,
                        Price = 0,
                        UseMoney = 0,
                        UseIntegral = 0,
                        UseScore = 0,
                        Zhe = 0,
                        GoodsId = 0,
                        Num = 0,
                        GoodsPrice = 0,
                        GoodsTitle = string.Empty,
                        GoodsImgurl = string.Empty,
                        PrizeNum = 0,
                        Status = 0,
                        PayType = 0,
                        OrderType = 10,
                        CreatedAt = DateTime.UtcNow
                    };
                    _dbContext.Orders.Add(order);
                    await _dbContext.SaveChangesAsync();

                    // Create order item
                    var orderItem = new OrderItem
                    {
                        OrderId = 0,
                        UserId = userId,
                        Status = 0,
                        GoodsId = 0,
                        Num = 0,
                        ShangId = selectedPrize.PrizeLevelId ?? 0,
                        GoodslistId = 0,
                        GoodslistTitle = selectedPrize.Title,
                        GoodslistImgurl = selectedPrize.ImgUrl ?? string.Empty,
                        GoodslistPrice = selectedPrize.JiangPrice ?? 0,
                        GoodslistMoney = selectedPrize.Money ?? 0,
                        GoodslistType = 1,
                        CreatedAt = DateTime.UtcNow,
                        PrizeCode = selectedPrize.PrizeCode ?? string.Empty,
                        OrderType = 10,
                        LuckNo = 0
                    };
                    _dbContext.OrderItems.Add(orderItem);

                    // Record user equity reward for prize
                    var userEquityReward = new UserEquityReward
                    {
                        UserId = userId,
                        EquityLevelId = equityLevel.Id,
                        EquityLevel = equityLevel.Level,
                        Type = 2,
                        Title = selectedPrize.Title,
                        ImgUrl = selectedPrize.ImgUrl,
                        PrizeLevelId = selectedPrize.PrizeLevelId,
                        JiangPrice = selectedPrize.JiangPrice,
                        Money = selectedPrize.Money,
                        ScMoney = selectedPrize.ScMoney,
                        PrizeCode = selectedPrize.PrizeCode,
                        Probability = selectedPrize.Probability,
                        CreatedAt = DateTime.UtcNow,
                        UpdatedAt = DateTime.UtcNow
                    };
                    _dbContext.UserEquityRewards.Add(userEquityReward);
                }
            }

            await _dbContext.SaveChangesAsync();
            await transaction.CommitAsync();

            _logger.LogInformation("User {UserId} claimed equity level {LevelId} rewards", userId, levelId);
            return new QuanYiLingResponse(rewards);
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "Failed to claim equity rewards for user {UserId}, level {LevelId}", userId, levelId);
            throw new InvalidOperationException("网络故障,请稍后再试");
        }
    }

    /// <summary>
    /// Get image URL with base URL
    /// </summary>
    private string GetImageUrl(string? path)
    {
        if (string.IsNullOrWhiteSpace(path))
            return string.Empty;

        if (path.StartsWith("http://") || path.StartsWith("https://"))
            return path;

        return $"{_imageBaseUrl}/{path.TrimStart('/')}";
    }

    /// <summary>
    /// Get QuanYi level info based on ou_qi_level and ou_qi
    /// </summary>
    private QuanYiLevelInfo GetQuanYiLevelInfo(int ouQiLevel, int ouQi, List<EquityLevel> equityLevelConfigs)
    {
        _logger.LogInformation("GetQuanYiLevelInfo called: ouQiLevel={OuQiLevel}, ouQi={OuQi}, configCount={ConfigCount}", 
            ouQiLevel, ouQi, equityLevelConfigs.Count);

        // 从数据库配置构建等级阈值
        var levelThresholds = equityLevelConfigs
            .ToDictionary(v => v.Level, v => v.Number);
        
        // 构建等级标题
        var levelTitles = equityLevelConfigs
            .ToDictionary(v => v.Level, v => v.Title ?? $"等级{v.Level}");

        _logger.LogInformation("Level thresholds from DB: {Thresholds}", 
            string.Join(", ", levelThresholds.Take(10).Select(kv => $"L{kv.Key}={kv.Value}")));

        // 如果没有配置，使用默认值
        if (!levelThresholds.Any())
        {
            _logger.LogWarning("No equity level configs found in database, using defaults");
            levelThresholds = new Dictionary<int, int>
            {
                { 0, 0 },
                { 1, 100 },
                { 2, 500 },
                { 3, 1000 },
                { 4, 3000 },
                { 5, 6000 },
                { 6, 10000 },
                { 7, 20000 }
            };
            levelTitles = new Dictionary<int, string>
            {
                { 0, "普通" },
                { 1, "青铜" },
                { 2, "白银" },
                { 3, "黄金" },
                { 4, "铂金" },
                { 5, "钻石" },
                { 6, "星耀" },
                { 7, "王者" }
            };
        }

        var title = levelTitles.GetValueOrDefault(ouQiLevel, "普通");
        var nextLevel = ouQiLevel + 1;
        var nextOuQi = levelThresholds.GetValueOrDefault(nextLevel, 0);
        var currentLevelOuQi = levelThresholds.GetValueOrDefault(ouQiLevel, 0);
        var maxLevel = levelThresholds.Keys.DefaultIfEmpty(0).Max();

        _logger.LogInformation("Level calculation: currentLevel={CurrentLevel}, nextLevel={NextLevel}, currentLevelOuQi={CurrentLevelOuQi}, nextOuQi={NextOuQi}, maxLevel={MaxLevel}",
            ouQiLevel, nextLevel, currentLevelOuQi, nextOuQi, maxLevel);

        // 计算差值和进度
        int cha;
        int jindu;
        if (nextLevel > maxLevel || nextOuQi == 0)
        {
            // 已满级
            cha = -1;
            jindu = 100;
            _logger.LogInformation("User is at max level");
        }
        else
        {
            cha = Math.Max(0, nextOuQi - ouQi);
            // 计算当前等级内的进度
            var levelRange = nextOuQi - currentLevelOuQi;
            var progress = ouQi - currentLevelOuQi;
            jindu = levelRange > 0 ? Math.Min(100, Math.Max(0, progress * 100 / levelRange)) : 0;
            _logger.LogInformation("Progress calculation: levelRange={LevelRange}, progress={Progress}, cha={Cha}, jindu={Jindu}",
                levelRange, progress, cha, jindu);
        }

        var result = new QuanYiLevelInfo
        {
            Level = ouQiLevel,
            Title = title,
            OuQi = ouQi,
            NextOuQi = nextOuQi,
            Cha = cha,
            Jindu = jindu
        };

        _logger.LogInformation("GetQuanYiLevelInfo result: Level={Level}, Title={Title}, OuQi={OuQi}, NextOuQi={NextOuQi}, Cha={Cha}, Jindu={Jindu}",
            result.Level, result.Title, result.OuQi, result.NextOuQi, result.Cha, result.Jindu);

        return result;
    }

    /// <summary>
    /// Generate order number
    /// </summary>
    private string GenerateOrderNo(string prefix)
    {
        var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        var random = new Random().Next(1000, 9999);
        return $"{prefix}{timestamp}{random}";
    }
}
