using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Knot.Contracts.Admin.Abstractions;
using Knot.Contracts.Auth.Infrastructure.Persistence;
using Knot.Contracts.Conversations.Domain;
using Knot.Contracts.Conversations.Infrastructure.Persistence;
using Knot.Contracts.Messaging.Application.Abstractions;
using Knot.Shared.Kernel.Storage;
using Knot.Contracts.Stories.Infrastructure.Persistence;
using Knot.Modules.Admin.Application.Admin.DTOs;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Knot.Modules.Admin.Application.Admin.Commands;

public record CleanRunCommand() : ICommand<MessageResponse>;

internal sealed class CleanRunCommandHandler : ICommandHandler<CleanRunCommand, MessageResponse>
{
    private readonly Knot.Contracts.Conversations.Infrastructure.Persistence.IChatsDbContext _chatsDbContext;
    private readonly Knot.Contracts.Messaging.Application.Abstractions.IMessageQueryService _messageQueryService;
    private readonly Knot.Contracts.Stories.Infrastructure.Persistence.IStoryCollection _storyCollection;
    private readonly IFileStorageService _fileStorage;
    private readonly Knot.Contracts.Auth.Infrastructure.Persistence.IAuthDbContext _identityDb;

    public CleanRunCommandHandler(
        Knot.Contracts.Conversations.Infrastructure.Persistence.IChatsDbContext chatsDbContext,
        Knot.Contracts.Messaging.Application.Abstractions.IMessageQueryService messageQueryService,
        Knot.Contracts.Stories.Infrastructure.Persistence.IStoryCollection storyCollection,
        IFileStorageService fileStorage,
        Knot.Contracts.Auth.Infrastructure.Persistence.IAuthDbContext identityDb)
    {
        _chatsDbContext = chatsDbContext;
        _messageQueryService = messageQueryService;
        _storyCollection = storyCollection;
        _fileStorage = fileStorage;
        _identityDb = identityDb;
    }

    public async Task<Result<MessageResponse>> Handle(CleanRunCommand request, CancellationToken cancellationToken)
    {
        try
        {
            var allChats = await _chatsDbContext.Chats.ToListAsync(cancellationToken);
            var activeChatIds = allChats.Select(c => c.Id).ToHashSet();

            var allMessages = await _messageQueryService.GetAllMessagesAsync(cancellationToken);
            var orphanMessages = await _messageQueryService.GetOrphanedMessagesAsync(activeChatIds, cancellationToken);

            var keptMessages = allMessages
                .Where(m => !orphanMessages.Any(om => om.Id == m.Id) && !m.IsDeleted)
                .ToList();

            var allMinioFiles = (await _fileStorage.ListFilesAsync()).ToList();

            var allUsers = await _identityDb.Users.ToListAsync(cancellationToken);

            var allStories = await _storyCollection.GetAllAsync(cancellationToken);

            var validUrls = new HashSet<string>();

            var activeMessageUrls = keptMessages
                .Where(m => m.Media != null)
                .SelectMany(m => m.Media!)
                .Select(me => me.Url)
                .Where(u => !string.IsNullOrEmpty(u));

            var activeChatUrls = allChats
                .Where(c => !string.IsNullOrEmpty(c.Avatar))
                .Select(c => c.Avatar!);

            var activeUserUrls = allUsers
                .Where(u => !string.IsNullOrEmpty(u.Avatar))
                .Select(u => u.Avatar!);

            var activeStoryUrls = allStories
                .Where(s => !string.IsNullOrEmpty(s.MediaUrl))
                .Select(s => s.MediaUrl!);

            foreach (var u in activeMessageUrls) validUrls.Add(u!);
            foreach (var u in activeChatUrls) validUrls.Add(u);
            foreach (var u in activeUserUrls) validUrls.Add(u);
            foreach (var u in activeStoryUrls) validUrls.Add(u);

            var validFileIds = validUrls
                .Where(u => u.Contains("/api/files/"))
                .Select(u => u.Split('/').Last())
                .ToHashSet();

            foreach (var file in allMinioFiles)
            {
                if (!validFileIds.Contains(file.FileId))
                {
                    await _fileStorage.DeleteFileAsync(file.FileId);
                }
            }

            if (orphanMessages.Any())
            {
                var orphanIds = orphanMessages.Select(m => m.Id).ToList();
                await _messageQueryService.DeleteMessagesAsync(orphanIds, cancellationToken);
            }

            return Result.Success(new MessageResponse("Cleanup completed successfully"));
        }
        catch (Exception ex)
        {
            return Result.Failure<MessageResponse>(new Error("Cleanup.ProcessError", $"Cleanup failed: {ex.Message}"));
        }
    }
}
