using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using RealCV.Application.DTOs;
using RealCV.Application.Interfaces;
using RealCV.Domain.Constants;
using RealCV.Domain.Enums;
using RealCV.Infrastructure.Data;

namespace RealCV.Infrastructure.Services;

public sealed class SubscriptionService : ISubscriptionService
{
    private readonly ApplicationDbContext _dbContext;
    private readonly ILogger<SubscriptionService> _logger;

    public SubscriptionService(
        ApplicationDbContext dbContext,
        ILogger<SubscriptionService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    public async Task<bool> CanPerformCheckAsync(Guid userId)
    {
        var user = await _dbContext.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(u => u.Id == userId);

        if (user == null)
        {
            _logger.LogWarning("User not found for quota check: {UserId}", userId);
            return false;
        }

        // Enterprise users have unlimited checks
        if (PlanLimits.IsUnlimited(user.Plan))
        {
            return true;
        }

        // Check if subscription is in good standing for paid plans
        if (user.Plan != UserPlan.Free)
        {
            if (user.SubscriptionStatus == "canceled" || user.SubscriptionStatus == "unpaid")
            {
                _logger.LogWarning(
                    "User {UserId} subscription status is {Status} - denying check",
                    userId, user.SubscriptionStatus);
                return false;
            }
        }

        var limit = PlanLimits.GetMonthlyLimit(user.Plan);
        var canPerform = user.ChecksUsedThisMonth < limit;

        if (!canPerform)
        {
            _logger.LogInformation(
                "User {UserId} has reached quota: {Used}/{Limit} checks",
                userId, user.ChecksUsedThisMonth, limit);
        }

        return canPerform;
    }

    public async Task IncrementUsageAsync(Guid userId)
    {
        var user = await _dbContext.Users.FindAsync(userId);
        if (user == null)
        {
            _logger.LogWarning("User not found for usage increment: {UserId}", userId);
            return;
        }

        user.ChecksUsedThisMonth++;
        await _dbContext.SaveChangesAsync();

        _logger.LogDebug(
            "Incremented usage for user {UserId}: {Count} checks this month",
            userId, user.ChecksUsedThisMonth);
    }

    public async Task ResetUsageAsync(Guid userId)
    {
        var user = await _dbContext.Users.FindAsync(userId);
        if (user == null)
        {
            _logger.LogWarning("User not found for usage reset: {UserId}", userId);
            return;
        }

        user.ChecksUsedThisMonth = 0;
        await _dbContext.SaveChangesAsync();

        _logger.LogInformation("Reset monthly usage for user {UserId}", userId);
    }

    public async Task<SubscriptionInfoDto> GetSubscriptionInfoAsync(Guid userId)
    {
        var user = await _dbContext.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(u => u.Id == userId);

        if (user == null)
        {
            _logger.LogWarning("User not found for subscription info: {UserId}", userId);
            return new SubscriptionInfoDto
            {
                Plan = UserPlan.Free,
                MonthlyLimit = PlanLimits.GetMonthlyLimit(UserPlan.Free),
                DisplayPrice = PlanLimits.GetDisplayPrice(UserPlan.Free)
            };
        }

        var limit = PlanLimits.GetMonthlyLimit(user.Plan);
        var isUnlimited = PlanLimits.IsUnlimited(user.Plan);

        return new SubscriptionInfoDto
        {
            Plan = user.Plan,
            ChecksUsedThisMonth = user.ChecksUsedThisMonth,
            MonthlyLimit = limit,
            ChecksRemaining = isUnlimited ? int.MaxValue : Math.Max(0, limit - user.ChecksUsedThisMonth),
            IsUnlimited = isUnlimited,
            SubscriptionStatus = user.SubscriptionStatus,
            CurrentPeriodEnd = user.CurrentPeriodEnd,
            HasActiveSubscription = !string.IsNullOrEmpty(user.StripeSubscriptionId) &&
                                   (user.SubscriptionStatus == "active" || user.SubscriptionStatus == "past_due"),
            DisplayPrice = PlanLimits.GetDisplayPrice(user.Plan)
        };
    }
}
