using System;
using System.IO;
using LiteDB;
using Serilog;
using Serilog.Events;

namespace Dacryptero.CopyDB
{
    public class Program
    {
        private static void Help()
        {
            Console.WriteLine(@"Copys the content of the original database to a new one

Dacryptero.CopyDB [source db] [target db] (key)

    source db: The source file name of a LiteDB database
    target db: The target file name (not allowed to exists)
    key: The database key
");
        }

        public static void Main(string[] args)
        {
            if (args.Length is < 2 or > 3)
            {
                Help();
                return;
            }
            if (!File.Exists(args[0]))
            {
                Console.Error.WriteLine("Source file does not exists");
                Help();
                return;
            }
            if (File.Exists(args[1]))
            {
                Console.Error.WriteLine("Target file does exists");
                Help();
                return;
            }

            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.Console(LogEventLevel.Verbose,
                    outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
                .CreateLogger();
            
            var tfi = new FileInfo(args[1]);
            if (!tfi.Directory!.Exists)
            {
                Log.Information("Create target dir {path}", tfi.Directory.FullName);
                tfi.Directory.Create();
            }

            var source = new LiteDatabase(new ConnectionString
            {
                Filename = args[0],
                Password = args.Length == 3 ? args[2] : null,
            });
            source.UtcDate = true;
            var target = new LiteDatabase(new ConnectionString
            {
                Filename = args[1],
                Password = args.Length == 3 ? args[2] : null,
                Collation = source.Collation,
            });
            target.UtcDate = true;
            target.UserVersion = source.UserVersion;
            foreach (var colName in source.GetCollectionNames())
            {
                Log.Information("copy collection {name}", colName);
                try
                {
                    var sourceCol = source.GetCollection(colName);
                    var targetCol = target.GetCollection(colName);
                    var sourceEnum = sourceCol.Query().ToEnumerable();
                    var count = targetCol.InsertBulk(sourceEnum);
                    Log.Information("{count:#,#0} items copied", count);
                }
                catch (Exception e)
                {
                    Log.Error(e, "Cannot copy collection");
                    target.DropCollection(colName);
                }
                Log.Information("Do Checkpoint");
                try { target.Checkpoint(); }
                catch (Exception e)
                {
                    Log.Error(e, "Cannot perform checkpoint - might the database corrupt?");
                }
            }
            source.Dispose();
            target.Dispose();
            Log.Information("Finished");
        }
    }
}