using Microsoft.Extensions.Logging;
using SharpChat.Messages;
using ZLogger;

namespace SharpChat;

public class StorageMigrator(ILogger logger, Storage source, Storage target) {
    public async Task Migrate(CancellationToken cancellationToken) {
        try {
            logger.ZLogInformation($"Converting from {source.GetType().Name} to {target.GetType().Name}!");
            logger.ZLogInformation($"Ensuring both source and target are fully upgraded...");
            if(cancellationToken.IsCancellationRequested) return;

            await source.UpgradeStorage();
            if(cancellationToken.IsCancellationRequested) return;

            await target.UpgradeStorage();
            if(cancellationToken.IsCancellationRequested) return;

            logger.ZLogInformation($"Creating message storage instances...");
            MessageStorage sourceMsgs = source.CreateMessageStorage();
            MessageStorage targetMsgs = target.CreateMessageStorage();

            if(cancellationToken.IsCancellationRequested) return;
            long msgCount = await sourceMsgs.CountMessages(includeDeleted: true);
            if(msgCount < 1) {
                logger.ZLogInformation($"No messages to migrate, skipping...");
            } else {
                logger.ZLogInformation($"Migrating {msgCount} message{(msgCount == 1 ? "" : "s")}...");

                long migrated = 0;
                DateTimeOffset lastReport = DateTimeOffset.UtcNow;
                IEnumerable<Message> msgs = await sourceMsgs.GetMessages(take: null, includeDeleted: true);
                foreach(Message msg in msgs) {
                    if(cancellationToken.IsCancellationRequested) break;

                    await targetMsgs.LogMessage(msg);

                    ++migrated;
                    if(DateTimeOffset.UtcNow - lastReport > TimeSpan.FromMinutes(1)) {
                        lastReport = DateTimeOffset.UtcNow;
                        double completion = (double)migrated / msgCount;
                        logger.ZLogInformation($"{migrated} of {msgCount} message{(migrated == 1 ? "" : "s")} migrated ({completion:P2})...");
                    }
                }

                logger.ZLogInformation($"Migrated {migrated} message{(migrated == 1 ? "" : "s")}!");
            }
        } catch(Exception ex) {
            logger.ZLogError($"Error during migration: {ex}");
            throw;
        }
    }
}