using Ikar.Server.Data;
using Ikar.Server.Data.Entities;
using Ikar.Server.Infrastructure.Storage;
using Ikar.Shared;
using Microsoft.EntityFrameworkCore;

namespace Ikar.Server.Infrastructure.Channels;

internal static class ChannelDiscussionMessageFactory
{
    public static async Task<Message?> CreateLinkedDiscussionRootAsync(
        IkarDbContext dbContext,
        AttachmentStorageService? attachmentStorageService,
        Chat channel,
        Message channelMessage,
        User sender,
        DateTimeOffset sentAt,
        CancellationToken cancellationToken)
    {
        if (channel.Type != ChatType.Channel ||
            !channelMessage.PostedAsChannel ||
            channel.LinkedDiscussionChatId is null)
        {
            return null;
        }

        var discussionChat = await dbContext.Chats
            .Include(x => x.Members)
            .FirstOrDefaultAsync(
                x => x.Id == channel.LinkedDiscussionChatId.Value &&
                     x.Type == ChatType.Group,
                cancellationToken);
        if (discussionChat is null)
        {
            return null;
        }

        var rootMessage = new Message
        {
            ChatId = discussionChat.Id,
            Chat = discussionChat,
            SenderId = sender.Id,
            Sender = sender,
            Text = BuildDiscussionRootText(channelMessage),
            SentAt = sentAt,
            ForwardedFromDisplayName = string.IsNullOrWhiteSpace(channel.Title) ? "Channel" : channel.Title,
            MediaAlbumId = channelMessage.MediaAlbumId,
            HasProtectedContent = channelMessage.HasProtectedContent,
            TtlSeconds = channelMessage.TtlSeconds,
            ExpiresAt = channelMessage.ExpiresAt
        };

        var clonedAttachments = new List<MessageAttachment>();
        try
        {
            foreach (var sourceAttachment in channelMessage.Attachments
                         .OrderBy(x => x.SortOrder)
                         .ThenBy(x => x.OriginalFileName))
            {
                if (attachmentStorageService is null)
                {
                    throw new InvalidOperationException("Attachment storage is required to mirror channel attachments to a discussion group.");
                }

                var clonedAttachment = await attachmentStorageService.CloneAsync(
                    rootMessage.Id,
                    sourceAttachment,
                    cancellationToken,
                    sourceAttachment.SortOrder);
                clonedAttachments.Add(clonedAttachment);
                rootMessage.Attachments.Add(clonedAttachment);
            }
        }
        catch
        {
            foreach (var clonedAttachment in clonedAttachments)
            {
                attachmentStorageService?.DeleteIfExists(clonedAttachment.StoragePath);
            }

            throw;
        }

        discussionChat.LastActivityAt = sentAt;
        dbContext.Messages.Add(rootMessage);
        return rootMessage;
    }

    public static string BuildDiscussionRootText(Message channelMessage)
    {
        var text = channelMessage.Text.Trim();
        return string.IsNullOrWhiteSpace(text) ? "Publication" : text;
    }
}
