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

namespace HoneyBox.Core.Services;

/// <summary>
/// 统一支付服务实现
/// </summary>
public class PaymentService : IPaymentService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<PaymentService> _logger;

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

    #region 资产扣减

    /// <inheritdoc />
    public async Task<AssetDeductionResult> DeductBalanceAsync(int userId, decimal amount, string content, string? orderNum = null, byte type = 3, int shareUid = 0)
    {
        if (amount <= 0)
        {
            return new AssetDeductionResult { Success = true, Message = "无需扣减" };
        }

        try
        {
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
            {
                return new AssetDeductionResult { Success = false, Message = "用户不存在" };
            }

            if (user.Money < amount)
            {
                return new AssetDeductionResult { Success = false, Message = "余额不足" };
            }

            // 扣减余额 - 使用精确计算
            var newBalance = user.Money - amount;
            user.Money = newBalance;
            user.UpdatedAt = DateTime.Now;

            // 记录余额变动
            var profitMoney = new ProfitMoney
            {
                UserId = userId,
                ChangeMoney = -amount, // 负数表示扣减
                Money = newBalance,
                Type = type,
                Content = content ?? string.Empty,
                ShareUid = shareUid,
                Other = orderNum,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitMoneys.Add(profitMoney);
            await _dbContext.SaveChangesAsync();

            _logger.LogDebug("扣减余额成功: UserId={UserId}, Amount={Amount}, NewBalance={NewBalance}, Type={Type}",
                userId, amount, newBalance, type);

            return new AssetDeductionResult
            {
                Success = true,
                Message = "扣减成功",
                RemainingBalance = newBalance
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "扣减余额失败: UserId={UserId}, Amount={Amount}", userId, amount);
            return new AssetDeductionResult { Success = false, Message = $"扣减失败: {ex.Message}" };
        }
    }

    /// <inheritdoc />
    public async Task<AssetDeductionResult> DeductIntegralAsync(int userId, decimal amount, string content, string? orderNum = null, byte type = 2, int shareUid = 0)
    {
        if (amount <= 0)
        {
            return new AssetDeductionResult { Success = true, Message = "无需扣减" };
        }

        try
        {
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
            {
                return new AssetDeductionResult { Success = false, Message = "用户不存在" };
            }

            if (user.Integral < amount)
            {
                return new AssetDeductionResult { Success = false, Message = "积分不足" };
            }

            // 扣减积分 - 使用精确计算
            var newBalance = user.Integral - amount;
            user.Integral = newBalance;
            user.UpdatedAt = DateTime.Now;

            // 记录积分变动
            var profitIntegral = new ProfitIntegral
            {
                UserId = userId,
                ChangeMoney = -amount, // 负数表示扣减
                Money = newBalance,
                Type = type,
                Content = content ?? string.Empty,
                ShareUid = shareUid,
                Other = orderNum,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitIntegrals.Add(profitIntegral);
            await _dbContext.SaveChangesAsync();

            _logger.LogDebug("扣减积分成功: UserId={UserId}, Amount={Amount}, NewBalance={NewBalance}, Type={Type}",
                userId, amount, newBalance, type);

            return new AssetDeductionResult
            {
                Success = true,
                Message = "扣减成功",
                RemainingBalance = newBalance
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "扣减积分失败: UserId={UserId}, Amount={Amount}", userId, amount);
            return new AssetDeductionResult { Success = false, Message = $"扣减失败: {ex.Message}" };
        }
    }

    /// <inheritdoc />
    public async Task<AssetDeductionResult> DeductMoney2Async(int userId, decimal amount, string content, string? orderNum = null, byte type = 3, int shareUid = 0)
    {
        if (amount <= 0)
        {
            return new AssetDeductionResult { Success = true, Message = "无需扣减" };
        }

        try
        {
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
            {
                return new AssetDeductionResult { Success = false, Message = "用户不存在" };
            }

            var currentMoney2 = user.Money2 ?? 0;
            if (currentMoney2 < amount)
            {
                return new AssetDeductionResult { Success = false, Message = "哈尼券不足" };
            }

            // 扣减哈尼券 - 使用精确计算
            var newBalance = currentMoney2 - amount;
            user.Money2 = newBalance;
            user.UpdatedAt = DateTime.Now;

            // 记录哈尼券变动
            var profitMoney2 = new ProfitMoney2
            {
                UserId = userId,
                ChangeMoney = -amount, // 负数表示扣减
                Money = newBalance,
                Type = type,
                Content = content ?? string.Empty,
                ShareUid = shareUid,
                Other = orderNum,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitMoney2s.Add(profitMoney2);
            await _dbContext.SaveChangesAsync();

            _logger.LogDebug("扣减哈尼券成功: UserId={UserId}, Amount={Amount}, NewBalance={NewBalance}, Type={Type}",
                userId, amount, newBalance, type);

            return new AssetDeductionResult
            {
                Success = true,
                Message = "扣减成功",
                RemainingBalance = newBalance
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "扣减哈尼券失败: UserId={UserId}, Amount={Amount}", userId, amount);
            return new AssetDeductionResult { Success = false, Message = $"扣减失败: {ex.Message}" };
        }
    }

    #endregion

    #region 资产增加

    /// <inheritdoc />
    public async Task<bool> AddBalanceAsync(int userId, decimal amount, string content, string? orderNum = null, byte type = 2, int shareUid = 0)
    {
        if (amount <= 0)
        {
            _logger.LogWarning("增加余额金额必须大于0: UserId={UserId}, Amount={Amount}", userId, amount);
            return false;
        }

        try
        {
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
            {
                _logger.LogWarning("增加余额时未找到用户: UserId={UserId}", userId);
                return false;
            }

            // 增加余额 - 使用精确计算
            var newBalance = user.Money + amount;
            user.Money = newBalance;
            user.UpdatedAt = DateTime.Now;

            // 记录余额变动
            var profitMoney = new ProfitMoney
            {
                UserId = userId,
                ChangeMoney = amount, // 正数表示增加
                Money = newBalance,
                Type = type,
                Content = content ?? string.Empty,
                ShareUid = shareUid,
                Other = orderNum,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitMoneys.Add(profitMoney);
            await _dbContext.SaveChangesAsync();

            _logger.LogInformation("增加余额成功: UserId={UserId}, Amount={Amount}, NewBalance={NewBalance}, Type={Type}",
                userId, amount, newBalance, type);

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "增加余额失败: UserId={UserId}, Amount={Amount}", userId, amount);
            return false;
        }
    }

    /// <inheritdoc />
    public async Task<bool> AddIntegralAsync(int userId, decimal amount, string content, string? orderNum = null, byte type = 4, int shareUid = 0)
    {
        if (amount <= 0)
        {
            _logger.LogWarning("增加积分金额必须大于0: UserId={UserId}, Amount={Amount}", userId, amount);
            return false;
        }

        try
        {
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
            {
                _logger.LogWarning("增加积分时未找到用户: UserId={UserId}", userId);
                return false;
            }

            // 增加积分 - 使用精确计算
            var newBalance = user.Integral + amount;
            user.Integral = newBalance;
            user.UpdatedAt = DateTime.Now;

            // 记录积分变动
            var profitIntegral = new ProfitIntegral
            {
                UserId = userId,
                ChangeMoney = amount, // 正数表示增加
                Money = newBalance,
                Type = type,
                Content = content ?? string.Empty,
                ShareUid = shareUid,
                Other = orderNum,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitIntegrals.Add(profitIntegral);
            await _dbContext.SaveChangesAsync();

            _logger.LogInformation("增加积分成功: UserId={UserId}, Amount={Amount}, NewBalance={NewBalance}, Type={Type}",
                userId, amount, newBalance, type);

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "增加积分失败: UserId={UserId}, Amount={Amount}", userId, amount);
            return false;
        }
    }

    /// <inheritdoc />
    public async Task<bool> AddMoney2Async(int userId, decimal amount, string content, string? orderNum = null, byte type = 5, int shareUid = 0)
    {
        if (amount <= 0)
        {
            _logger.LogWarning("增加哈尼券金额必须大于0: UserId={UserId}, Amount={Amount}", userId, amount);
            return false;
        }

        try
        {
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
            {
                _logger.LogWarning("增加哈尼券时未找到用户: UserId={UserId}", userId);
                return false;
            }

            // 增加哈尼券 - 使用精确计算
            var currentMoney2 = user.Money2 ?? 0;
            var newBalance = currentMoney2 + amount;
            user.Money2 = newBalance;
            user.UpdatedAt = DateTime.Now;

            // 记录哈尼券变动
            var profitMoney2 = new ProfitMoney2
            {
                UserId = userId,
                ChangeMoney = amount, // 正数表示增加
                Money = newBalance,
                Type = type,
                Content = content ?? string.Empty,
                ShareUid = shareUid,
                Other = orderNum,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitMoney2s.Add(profitMoney2);
            await _dbContext.SaveChangesAsync();

            _logger.LogInformation("增加哈尼券成功: UserId={UserId}, Amount={Amount}, NewBalance={NewBalance}, Type={Type}",
                userId, amount, newBalance, type);

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "增加哈尼券失败: UserId={UserId}, Amount={Amount}", userId, amount);
            return false;
        }
    }

    #endregion

    #region 支付记录

    /// <inheritdoc />
    public async Task<bool> RecordPaymentAsync(int userId, string orderNum, decimal amount, PaymentType payType, string content)
    {
        try
        {
            var record = new ProfitPay
            {
                UserId = userId,
                OrderNum = orderNum,
                ChangeMoney = amount,
                Content = content,
                PayType = (byte)payType,
                CreatedAt = DateTime.Now
            };

            _dbContext.ProfitPays.Add(record);
            await _dbContext.SaveChangesAsync();
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "记录支付流水失败: UserId={UserId}, OrderNum={OrderNum}", userId, orderNum);
            return false;
        }
    }

    /// <inheritdoc />
    public async Task<List<PaymentRecordDto>> GetPaymentRecordsAsync(int userId, int page = 1, int pageSize = 10)
    {
        var records = await _dbContext.ProfitPays
            .Where(p => p.UserId == userId)
            .OrderByDescending(p => p.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(p => new PaymentRecordDto
            {
                Id = p.Id,
                UserId = p.UserId,
                OrderNum = p.OrderNum,
                ChangeMoney = p.ChangeMoney.ToString("F2"),
                Content = p.Content,
                PayType = p.PayType,
                PayTypeText = GetPayTypeText(p.PayType),
                CreatedAt = new DateTimeOffset(p.CreatedAt).ToUnixTimeSeconds()
            })
            .ToListAsync();

        return records;
    }

    /// <inheritdoc />
    public async Task<bool> HasPaymentRecordAsync(string orderNum)
    {
        if (string.IsNullOrEmpty(orderNum))
        {
            return false;
        }

        return await _dbContext.ProfitPays.AnyAsync(p => p.OrderNum == orderNum);
    }

    /// <inheritdoc />
    public async Task<PaymentRecordDto?> GetPaymentRecordByOrderNumAsync(string orderNum)
    {
        if (string.IsNullOrEmpty(orderNum))
        {
            return null;
        }

        var record = await _dbContext.ProfitPays
            .Where(p => p.OrderNum == orderNum)
            .OrderByDescending(p => p.CreatedAt)
            .FirstOrDefaultAsync();

        if (record == null)
        {
            return null;
        }

        return new PaymentRecordDto
        {
            Id = record.Id,
            UserId = record.UserId,
            OrderNum = record.OrderNum,
            ChangeMoney = record.ChangeMoney.ToString("F2"),
            Content = record.Content,
            PayType = record.PayType,
            PayTypeText = GetPayTypeText(record.PayType),
            CreatedAt = new DateTimeOffset(record.CreatedAt).ToUnixTimeSeconds()
        };
    }

    #endregion

    #region 余额验证

    /// <inheritdoc />
    public async Task<bool> ValidateBalanceAsync(int userId, decimal amount)
    {
        var user = await _dbContext.Users.FindAsync(userId);
        return user != null && user.Money >= amount;
    }

    /// <inheritdoc />
    public async Task<bool> ValidateIntegralAsync(int userId, decimal amount)
    {
        var user = await _dbContext.Users.FindAsync(userId);
        return user != null && user.Integral >= amount;
    }

    /// <inheritdoc />
    public async Task<bool> ValidateMoney2Async(int userId, decimal amount)
    {
        var user = await _dbContext.Users.FindAsync(userId);
        return user != null && user.Money2 >= amount;
    }

    #endregion

    #region 私有方法

    private static string GetPayTypeText(int payType)
    {
        return payType switch
        {
            1 => "微信支付",
            2 => "余额支付",
            3 => "积分支付",
            4 => "哈尼券支付",
            _ => "未知"
        };
    }

    #endregion
}
