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

namespace HoneyBox.Core.Services;

/// <summary>
/// 兑换码服务实现
/// </summary>
public class RedeemService : IRedeemService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<RedeemService> _logger;

    public RedeemService(HoneyBoxDbContext dbContext, ILogger<RedeemService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<RedeemResult> UseRedeemCodeAsync(int userId, string code)
    {
        _logger.LogInformation("使用兑换码: UserId={UserId}, Code={Code}", userId, code);

        if (string.IsNullOrWhiteSpace(code))
        {
            return new RedeemResult
            {
                Success = false,
                Message = "请输入兑换码"
            };
        }

        // 查找兑换码
        var redeemCode = await _dbContext.RedeemCodes
            .FirstOrDefaultAsync(r => r.Code == code.Trim());

        if (redeemCode == null)
        {
            _logger.LogWarning("兑换码不存在: Code={Code}", code);
            return new RedeemResult
            {
                Success = false,
                Message = "兑换码无效"
            };
        }

        // 检查是否已使用
        if (redeemCode.Status == 1)
        {
            _logger.LogWarning("兑换码已被使用: Code={Code}", code);
            return new RedeemResult
            {
                Success = false,
                Message = "兑换码已被使用"
            };
        }

        // 检查是否过期
        if (redeemCode.ExpiredAt.HasValue && redeemCode.ExpiredAt.Value < DateTime.Now)
        {
            _logger.LogWarning("兑换码已过期: Code={Code}, ExpiredAt={ExpiredAt}", code, redeemCode.ExpiredAt);
            return new RedeemResult
            {
                Success = false,
                Message = "兑换码已过期"
            };
        }

        // 获取用户
        var user = await _dbContext.Users.FindAsync(userId);
        if (user == null)
        {
            _logger.LogWarning("用户不存在: UserId={UserId}", userId);
            return new RedeemResult
            {
                Success = false,
                Message = "用户不存在"
            };
        }

        using var transaction = await _dbContext.Database.BeginTransactionAsync();
        try
        {
            // 根据奖励类型发放奖励
            var rewardAmount = redeemCode.RewardAmount;
            var rewardType = redeemCode.RewardType.ToLower();
            var rewardTypeName = GetRewardTypeName(rewardType);

            switch (rewardType)
            {
                case "money":
                    await ChangeMoneyAsync(user, rewardAmount, "兑换码奖励");
                    break;
                case "integral":
                    await ChangeIntegralAsync(user, rewardAmount, "兑换码奖励");
                    break;
                case "score":
                    await ChangeScoreAsync(user, rewardAmount, "兑换码奖励");
                    break;
                default:
                    _logger.LogWarning("未知的奖励类型: RewardType={RewardType}", rewardType);
                    return new RedeemResult
                    {
                        Success = false,
                        Message = "兑换码配置错误"
                    };
            }

            // 更新兑换码状态
            redeemCode.Status = 1;
            redeemCode.UsedByUserId = userId;
            redeemCode.UsedAt = DateTime.Now;

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

            _logger.LogInformation("兑换码使用成功: UserId={UserId}, Code={Code}, RewardType={RewardType}, RewardAmount={RewardAmount}",
                userId, code, rewardType, rewardAmount);

            return new RedeemResult
            {
                Success = true,
                Message = $"兑换成功，获得{rewardAmount}{rewardTypeName}",
                RewardType = rewardType,
                RewardAmount = rewardAmount
            };
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "兑换码使用失败: UserId={UserId}, Code={Code}", userId, code);
            return new RedeemResult
            {
                Success = false,
                Message = "兑换失败，请稍后重试"
            };
        }
    }

    /// <inheritdoc />
    public async Task<RedeemRecordResponse> GetRedeemRecordAsync(int userId, int page = 1, int pageSize = 10)
    {
        _logger.LogInformation("获取兑换记录: UserId={UserId}, Page={Page}, PageSize={PageSize}", userId, page, pageSize);

        // 确保分页参数有效
        if (page < 1) page = 1;
        if (pageSize < 1) pageSize = 10;
        if (pageSize > 50) pageSize = 50;

        // 查询用户已使用的兑换码
        var query = _dbContext.RedeemCodes
            .Where(r => r.UsedByUserId == userId && r.Status == 1)
            .OrderByDescending(r => r.UsedAt);

        // 获取总数
        var total = await query.CountAsync();

        // 分页查询
        var records = await query
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(r => new RedeemRecordItem
            {
                Id = r.Id,
                Code = MaskCode(r.Code),
                RewardType = r.RewardType,
                RewardTypeName = GetRewardTypeNameStatic(r.RewardType),
                RewardAmount = r.RewardAmount,
                UsedAt = r.UsedAt,
                Remark = r.Remark
            })
            .ToListAsync();

        return new RedeemRecordResponse
        {
            List = records,
            Total = total,
            Page = page,
            PageSize = pageSize
        };
    }

    #region Private Methods

    /// <summary>
    /// 获取奖励类型名称
    /// </summary>
    private static string GetRewardTypeName(string rewardType)
    {
        return rewardType.ToLower() switch
        {
            "money" => "余额",
            "integral" => "吧唧币",
            "score" => "积分",
            _ => "奖励"
        };
    }

    /// <summary>
    /// 获取奖励类型名称（静态方法，用于LINQ查询）
    /// </summary>
    private static string GetRewardTypeNameStatic(string rewardType)
    {
        return rewardType.ToLower() switch
        {
            "money" => "余额",
            "integral" => "吧唧币",
            "score" => "积分",
            _ => "奖励"
        };
    }

    /// <summary>
    /// 隐藏兑换码中间部分
    /// </summary>
    private static string MaskCode(string code)
    {
        if (string.IsNullOrEmpty(code) || code.Length <= 4)
        {
            return code;
        }

        // 保留前2位和后2位，中间用*替换
        var visibleLength = 2;
        var maskedLength = code.Length - visibleLength * 2;
        if (maskedLength <= 0)
        {
            return code;
        }

        return code.Substring(0, visibleLength) + new string('*', maskedLength) + code.Substring(code.Length - visibleLength);
    }

    /// <summary>
    /// 变更用户余额
    /// </summary>
    private async Task ChangeMoneyAsync(User user, decimal amount, string content)
    {
        user.Money += amount;
        user.UpdatedAt = DateTime.Now;

        var profitMoney = new ProfitMoney
        {
            UserId = user.Id,
            ChangeMoney = amount,
            Money = user.Money,
            Type = 10, // 兑换码奖励类型
            Content = content,
            ShareUid = 0,
            CreatedAt = DateTime.Now
        };
        _dbContext.ProfitMoneys.Add(profitMoney);
    }

    /// <summary>
    /// 变更用户吧唧币
    /// </summary>
    private async Task ChangeIntegralAsync(User user, decimal amount, string content)
    {
        user.Integral += amount;
        user.UpdatedAt = DateTime.Now;

        var profitIntegral = new ProfitIntegral
        {
            UserId = user.Id,
            ChangeMoney = amount,
            Money = user.Integral,
            Type = 10, // 兑换码奖励类型
            Content = content,
            ShareUid = 0,
            CreatedAt = DateTime.Now
        };
        _dbContext.ProfitIntegrals.Add(profitIntegral);
    }

    /// <summary>
    /// 变更用户积分
    /// </summary>
    private async Task ChangeScoreAsync(User user, decimal amount, string content)
    {
        user.Score += amount;
        user.UpdatedAt = DateTime.Now;

        var profitScore = new ProfitScore
        {
            UserId = user.Id,
            ChangeMoney = amount,
            Money = user.Score,
            Type = 10, // 兑换码奖励类型
            Content = content,
            ShareUid = 0,
            CreatedAt = DateTime.Now
        };
        _dbContext.ProfitScores.Add(profitScore);
    }

    #endregion
}
