using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Domain.Media;

namespace TeleWave.Application.Media.ManualInbox;

public sealed class ListManualInboxQueryHandler(IAppDbContext dbContext, IMediaStorage storage)
    : IQueryHandler<ListManualInboxQuery, ManualInboxListDto>
{
    /// <summary>Потолок выдачи: каталог наполняет человек, и он может оказаться огромным.</summary>
    private const int MaxFiles = 500;

    public async Task<ManualInboxListDto> Handle(
        ListManualInboxQuery query,
        CancellationToken cancellationToken
    )
    {
        // Субтитры, nfo и обложки в списке не нужны: выбрать их всё равно нельзя, а рядом с сериями
        // они превращают список в кашу. Спутников по имени импорт подчистит сам.
        var files = storage
            .ListManualInbox(int.MaxValue)
            .Where(f => MediaFormats.IsAllowed(f.Name))
            .Take(MaxFiles + 1)
            .ToList();

        var truncated = files.Count > MaxFiles;
        var page = truncated ? files.Take(MaxFiles).ToList() : files;
        if (page.Count == 0)
            return new ManualInboxListDto([], false);

        // Дедуп — по имени файла, тем же правилом, что и при регистрации ассета.
        var names = page.Select(f => f.Name).Distinct().ToList();
        var taken = await dbContext
            .MediaAssets.AsNoTracking()
            .Where(a => names.Contains(a.OriginalFileName) && a.Status != MediaAssetStatus.Failed)
            .Select(a => a.OriginalFileName)
            .ToListAsync(cancellationToken);
        var takenSet = taken.ToHashSet(StringComparer.Ordinal);

        return new ManualInboxListDto(
            page.Select(f => new ManualInboxFileDto(
                    f.RelativePath,
                    Folder(f.RelativePath),
                    f.Name,
                    f.SizeBytes,
                    takenSet.Contains(f.Name)
                ))
                .ToList(),
            truncated
        );
    }

    /// <summary>Каталог файла внутри manual/ — пустая строка для файлов в корне.</summary>
    private static string Folder(string relativePath)
    {
        var slash = relativePath.LastIndexOf('/');
        return slash < 0 ? string.Empty : relativePath[..slash];
    }
}
