using ZB.MOM.WW.CBDD.Core.Storage;
using ZB.MOM.WW.CBDD.Core.Transactions;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Context;
using System.Diagnostics;

namespace ZB.MOM.WW.CBDD.CheckpointTest;

/// <summary>
/// Quick test to verify checkpoint functionality and performance improvement
/// </summary>
class Program
{
    static void Main(string[] args)
    {
        var serilogLogger = new LoggerConfiguration()
            .Enrich.FromLogContext()
            .WriteTo.Console()
            .CreateLogger();

        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.ClearProviders();
            builder.AddSerilog(serilogLogger, dispose: true);
        });

        var logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("=== DocumentDb Checkpoint Performance Test ===");

        var dbPath = "test_checkpoint.db";
        var walPath = "test_checkpoint.wal";

        using var _ = LogContext.PushProperty("DatabasePath", dbPath);
        using var __ = LogContext.PushProperty("WalPath", walPath);

        if (File.Exists(dbPath))
        {
            File.Delete(dbPath);
        }

        if (File.Exists(walPath))
        {
            File.Delete(walPath);
        }

        using var storage = new StorageEngine(dbPath, PageFileConfig.Default);

        logger.LogInformation("1. Testing Single Inserts ({TransactionCount} transactions)...", 500);
        var sw = Stopwatch.StartNew();
        
        using (LogContext.PushProperty("Phase", "SingleInserts"))
        {
        for (int i = 0; i < 500; i++)
        {
            using var txn = storage.BeginTransaction();
            
            // Simulate a write
            var pageId = storage.AllocatePage();
            var data = new byte[storage.PageSize];
            new Random().NextBytes(data);
            
            // Write directly to storage
            // Old: txn.AddWrite(...)
            storage.WritePage(pageId, txn.TransactionId, data);
            
            storage.CommitTransaction(txn);
        }
        }
        
        sw.Stop();
        logger.LogInformation("Completed {TransactionCount} inserts in {ElapsedMs}ms", 500, sw.ElapsedMilliseconds);
        logger.LogInformation("Average: {InsertsPerSecond:F0} inserts/sec", 500.0 / sw.Elapsed.TotalSeconds);
        
        var walSize = new FileInfo(walPath).Length;
        logger.LogInformation("WAL size: {WalSizeKb:F1} KB", walSize / 1024.0);

        logger.LogInformation("2. Performing Manual Checkpoint...");
        sw.Restart();
        storage.Checkpoint();
        sw.Stop();
        
        logger.LogInformation("Checkpoint completed in {ElapsedMs}ms", sw.ElapsedMilliseconds);
        
        var dbSize = new FileInfo(dbPath).Length;
        var walSizeAfter = new FileInfo(walPath).Length;
        logger.LogInformation("DB size: {DbSizeKb:F1} KB", dbSize / 1024.0);
        logger.LogInformation("WAL size after checkpoint: {WalSizeKb:F1} KB", walSizeAfter / 1024.0);

        logger.LogInformation("3. Testing Checkpoint with Truncate (Integrated)...");
        storage.Checkpoint();
        
        walSizeAfter = new FileInfo(walPath).Length;
        logger.LogInformation("WAL size after truncate: {WalSizeKb:F1} KB", walSizeAfter / 1024.0);

        logger.LogInformation("4. Testing Batch Inserts ({TransactionCount} transactions)...", 1000);
        sw.Restart();
        
        using (LogContext.PushProperty("Phase", "BatchInserts"))
        {
        for (int i = 0; i < 1000; i++)
        {
            using var txn = storage.BeginTransaction();
            
            var pageId = storage.AllocatePage();
            var data = new byte[storage.PageSize];
            new Random().NextBytes(data);
            
            storage.WritePage(pageId, txn.TransactionId, data);
            
            storage.CommitTransaction(txn);
        }
        }
        
        sw.Stop();
        logger.LogInformation("Completed {TransactionCount} inserts in {ElapsedMs}ms", 1000, sw.ElapsedMilliseconds);
        logger.LogInformation("Average: {InsertsPerSecond:F0} inserts/sec", 1000.0 / sw.Elapsed.TotalSeconds);
        
        walSize = new FileInfo(walPath).Length;
        logger.LogInformation("WAL size: {WalSizeKb:F1} KB", walSize / 1024.0);

        logger.LogInformation("5. Final checkpoint and cleanup...");
        storage.Checkpoint();
        
        dbSize = new FileInfo(dbPath).Length;
        walSizeAfter = new FileInfo(walPath).Length;
        logger.LogInformation("Final DB size: {DbSizeKb:F1} KB", dbSize / 1024.0);
        logger.LogInformation("Final WAL size: {WalSizeKb:F1} KB", walSizeAfter / 1024.0);

        logger.LogInformation("=== Test Completed Successfully! ===");
        logger.LogInformation("Key Observations:");
        logger.LogInformation("- Commits are fast (only WAL writes)");
        logger.LogInformation("- Checkpoint consolidates changes to DB");
        logger.LogInformation("- Truncate reclaims WAL space");
        logger.LogInformation("Press any key to exit...");
        Console.ReadKey();

        // Cleanup
        try
        {
            if (File.Exists(dbPath)) File.Delete(dbPath);
            if (File.Exists(walPath)) File.Delete(walPath);
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Cleanup after checkpoint test failed");
        }
    }
}
