using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Knot.Contracts.Conversations.Application.Abstractions;
using Knot.Contracts.Conversations.Domain;
using Knot.Modules.TelegramImport.Application.Abstractions;
using Knot.Modules.TelegramImport.Infrastructure.Background;
using Knot.Shared.Kernel;

namespace Knot.Modules.TelegramImport.Application.TelegramImport;

public record ExecuteImportResponseDto(Guid JobId, string Status, Guid ChatId);

public record ExecuteImportCommand(
    Guid CurrentUserId,
    Guid Token,
    string? GroupName,
    Dictionary<string, Guid> Mapping,
    int TotalMessages = 0
) : ICommand<ExecuteImportResponseDto>;

internal sealed class ExecuteImportCommandHandler : ICommandHandler<ExecuteImportCommand, ExecuteImportResponseDto>
{
    private readonly TelegramImportWorker _worker;
    private readonly IImportJobStore _jobStore;
    private readonly IChatRepository _chatRepository;
    private readonly IChatsUnitOfWork _unitOfWork;
    private readonly ITelegramHtmlParser _htmlParser;

    public ExecuteImportCommandHandler(
        TelegramImportWorker worker, 
        IImportJobStore jobStore,
        IChatRepository chatRepository,
        IChatsUnitOfWork unitOfWork,
        ITelegramHtmlParser htmlParser)
    {
        _worker = worker;
        _jobStore = jobStore;
        _chatRepository = chatRepository;
        _unitOfWork = unitOfWork;
        _htmlParser = htmlParser;
    }

    public async Task<Result<ExecuteImportResponseDto>> Handle(ExecuteImportCommand request, CancellationToken cancellationToken)
    {
        if (!TelegramImportState.TempZips.TryGetValue(request.Token, out var tempPath))
        {
            return Result.Failure<ExecuteImportResponseDto>(new Error("Import.Expired", "Import session expired or file not found."));
        }

        var groupName = request.GroupName;
        if (string.IsNullOrEmpty(groupName))
        {
            try 
            {
                using var archive = ZipFile.OpenRead(tempPath);
                var firstHtml = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith(".html", StringComparison.OrdinalIgnoreCase));
                if (firstHtml != null)
                {
                    using var stream = firstHtml.Open();
                    groupName = await _htmlParser.ExtractGroupNameAsync(stream, cancellationToken);
                }
            }
            catch { }
        }

        // 1. Создаем чат сразу (синхронно), чтобы пользователь его увидел
        // 1. Создаем чат сразу (синхронно), чтобы пользователь его увидел
        var memberIdList = request.Mapping.Values.Where(v => v != Guid.Empty).Distinct().ToList();
        if (!memberIdList.Contains(request.CurrentUserId)) memberIdList.Add(request.CurrentUserId);
        var jobId = Guid.NewGuid();
        
        // Решаем какой тип чата: если 2 участника или 1 участник (Saved Messages)
        bool isPersonal = memberIdList.Count <= 2;
        var chatType = isPersonal ? ChatType.Personal : ChatType.Group;
        
        string finalChatName = groupName ?? "Telegram Import";
        if (isPersonal)
        {
            // Берем имя собеседника из маппинга
            var otherUserId = memberIdList.FirstOrDefault(id => id != request.CurrentUserId);
            var otherUserName = request.Mapping.FirstOrDefault(m => m.Value == otherUserId).Key;
            if (!string.IsNullOrEmpty(otherUserName)) finalChatName = otherUserName;
        }

        // 2. Создание чата (в скрытом состоянии)
        var chat = Chat.Create(finalChatName, chatType, isImporting: true, importJobId: jobId);
        chat.AddMember(request.CurrentUserId, ChatRole.Owner);
        
        foreach (var memberId in memberIdList)
        {
            if (memberId != request.CurrentUserId)
            {
                chat.AddMember(memberId, ChatRole.Member);
            }
        }

        _chatRepository.Add(chat);
        await _unitOfWork.SaveChangesAsync(cancellationToken);
        
        // 3. Фоновая обработка сообщений
        _ = _worker.ProcessImportAsync(request, jobId, chat.Id, tempPath, CancellationToken.None);

        _jobStore.AddOrUpdate(new ImportJobInfo 
        { 
            JobId = jobId, 
            Status = ImportJobStatus.Queued,
            TotalMessages = request.TotalMessages 
        });

        return Result.Success(new ExecuteImportResponseDto(jobId, "Processing", chat.Id));
    }
}
