using Microsoft.EntityFrameworkCore;
using DramaLing.Api.Data;
using DramaLing.Api.Models.Entities;

namespace DramaLing.Api.Repositories;

/// <summary>
/// 簡化的 Flashcard Repository 實作
/// </summary>
public class SimpleFlashcardRepository : BaseRepository<Flashcard>, IFlashcardRepository
{
    public SimpleFlashcardRepository(DramaLingDbContext context, ILogger<SimpleFlashcardRepository> logger)
        : base(context, logger)
    {
    }

    public async Task<IEnumerable<Flashcard>> GetFlashcardsByUserIdAsync(Guid userId)
    {
        return await _dbSet.AsNoTracking().Where(f => f.UserId == userId).ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetFlashcardsByCardSetIdAsync(Guid cardSetId)
    {
        return await _dbSet.AsNoTracking().Where(f => f.CardSetId == cardSetId).ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetDueFlashcardsAsync(Guid userId, DateTime dueDate)
    {
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId && f.NextReviewDate <= dueDate)
            .ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetFlashcardsByDifficultyAsync(Guid userId, string difficultyLevel)
    {
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId && f.DifficultyLevel == difficultyLevel)
            .ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetRecentlyAddedAsync(Guid userId, int count)
    {
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId)
            .OrderByDescending(f => f.CreatedAt)
            .Take(count)
            .ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetMostReviewedAsync(Guid userId, int count)
    {
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId)
            .OrderByDescending(f => f.TimesReviewed)
            .Take(count)
            .ToListAsync();
    }

    public async Task<int> GetTotalFlashcardsCountAsync(Guid userId)
    {
        return await _dbSet.CountAsync(f => f.UserId == userId && !f.IsArchived);
    }

    public async Task<int> GetMasteredFlashcardsCountAsync(Guid userId)
    {
        return await _dbSet.CountAsync(f => f.UserId == userId && f.MasteryLevel >= 5);
    }

    public async Task<Dictionary<string, int>> GetFlashcardsByDifficultyStatsAsync(Guid userId)
    {
        var stats = await _dbSet
            .Where(f => f.UserId == userId && !f.IsArchived)
            .GroupBy(f => f.DifficultyLevel)
            .Select(g => new { Level = g.Key, Count = g.Count() })
            .ToDictionaryAsync(x => x.Level ?? "Unknown", x => x.Count);

        return stats;
    }

    public async Task<IEnumerable<Flashcard>> SearchFlashcardsAsync(Guid userId, string searchTerm)
    {
        var term = searchTerm.ToLower();
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId &&
                       (f.Word.ToLower().Contains(term) || f.Translation.ToLower().Contains(term)))
            .ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetFavoriteFlashcardsAsync(Guid userId)
    {
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId && f.IsFavorite)
            .ToListAsync();
    }

    public async Task<IEnumerable<Flashcard>> GetArchivedFlashcardsAsync(Guid userId)
    {
        return await _dbSet.AsNoTracking()
            .Where(f => f.UserId == userId && f.IsArchived)
            .ToListAsync();
    }

    public async Task<bool> BulkUpdateMasteryLevelAsync(IEnumerable<Guid> flashcardIds, int newMasteryLevel)
    {
        try
        {
            var ids = flashcardIds.ToList();
            var flashcards = await _dbSet.Where(f => ids.Contains(f.Id)).ToListAsync();
            foreach (var flashcard in flashcards)
            {
                flashcard.MasteryLevel = newMasteryLevel;
                flashcard.UpdatedAt = DateTime.UtcNow;
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

    public async Task<bool> BulkUpdateNextReviewDateAsync(IEnumerable<Guid> flashcardIds, DateTime newDate)
    {
        try
        {
            var ids = flashcardIds.ToList();
            var flashcards = await _dbSet.Where(f => ids.Contains(f.Id)).ToListAsync();
            foreach (var flashcard in flashcards)
            {
                flashcard.NextReviewDate = newDate;
                flashcard.UpdatedAt = DateTime.UtcNow;
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

    public async Task<IEnumerable<Flashcard>> GetFlashcardsWithIncludesAsync(Guid userId,
        bool includeTags = false, bool includeStudyRecords = false)
    {
        var query = _dbSet.AsNoTracking().Where(f => f.UserId == userId);

        if (includeTags)
        {
            query = query.Include(f => f.FlashcardTags!);
        }

        return await query.ToListAsync();
    }
}