using Microsoft.EntityFrameworkCore;
using MissionService.Domain.AggregatesModel.CheckInAggregate;
using MissionService.Domain.SeedWork;

namespace MissionService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for UserCheckIn aggregate
/// VI: Triển khai repository cho UserCheckIn aggregate
/// </summary>
public class UserCheckInRepository : IUserCheckInRepository
{
    private readonly MissionDbContext _context;
    
    public IUnitOfWork UnitOfWork => _context;

    public UserCheckInRepository(MissionDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public UserCheckIn Add(UserCheckIn checkIn)
    {
        return _context.UserCheckIns.Add(checkIn).Entity;
    }

    public void Update(UserCheckIn checkIn)
    {
        _context.Entry(checkIn).State = EntityState.Modified;
    }

    public async Task<UserCheckIn?> GetByIdAsync(Guid id, CancellationToken ct = default)
    {
        return await _context.UserCheckIns
            .Include(c => c.CheckInDays)
            .FirstOrDefaultAsync(c => c.Id == id, ct);
    }

    public async Task<UserCheckIn?> GetByUserIdAsync(Guid userId, CancellationToken ct = default)
    {
        return await _context.UserCheckIns
            .Include(c => c.CheckInDays)
            .FirstOrDefaultAsync(c => c.UserId == userId, ct);
    }

    public async Task<UserCheckIn> GetOrCreateByUserIdAsync(Guid userId, CancellationToken ct = default)
    {
        var checkIn = await GetByUserIdAsync(userId, ct);
        
        if (checkIn == null)
        {
            checkIn = new UserCheckIn(userId);
            Add(checkIn);
        }
        
        return checkIn;
    }

    public async Task<IReadOnlyList<UserCheckIn>> GetActiveStreaksAsync(int minStreak, CancellationToken ct = default)
    {
        var yesterday = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(-1));
        var today = DateOnly.FromDateTime(DateTime.UtcNow);
        
        return await _context.UserCheckIns
            .Where(c => c.CurrentStreak >= minStreak)
            .Where(c => c.LastCheckInDate == yesterday || c.LastCheckInDate == today)
            .OrderByDescending(c => c.CurrentStreak)
            .ToListAsync(ct);
    }

    public async Task<IReadOnlyList<UserCheckIn>> GetTopStreaksAsync(int count, CancellationToken ct = default)
    {
        return await _context.UserCheckIns
            .OrderByDescending(c => c.LongestStreak)
            .ThenByDescending(c => c.TotalCheckIns)
            .Take(count)
            .ToListAsync(ct);
    }
}
