using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Toolchains.InProcess.Emit;
using MaddoShared.Benchmarks.Helpers;
using Microsoft.Extensions.Logging;

namespace MaddoShared.Benchmarks;

/// <summary>
/// Stress test benchmark for large-scale image processing
/// WARNING: This will generate a large number of images and may take significant time and disk space
/// </summary>
[MemoryDiagnoser]
[Config(typeof(InProcessConfig))]
public class StressTestBenchmark
{
    private string _sourceDirectory;
    private string _destinationDirectory;
    private ImageCreationStuff _imageCreationStuff;
    private PicSettings _picSettings;

    [Params(500, 1000)]
    public int ImageCount { get; set; }

    [GlobalSetup]
    public void Setup()
    {
        var tempBase = Path.Combine(Path.GetTempPath(), "StressTestBenchmarks", Guid.NewGuid().ToString());
        _sourceDirectory = Path.Combine(tempBase, "Source");
        _destinationDirectory = Path.Combine(tempBase, "Destination");

        Directory.CreateDirectory(_sourceDirectory);
        Directory.CreateDirectory(_destinationDirectory);

        Console.WriteLine($"[STRESS TEST] Generating {ImageCount} test images...");
        Console.WriteLine("This may take several minutes depending on your hardware.");
        
        // Use smaller images for stress test to save space and time
        TestImageGenerator.GenerateTestImages(_sourceDirectory, ImageCount, width: 1920, height: 1080);

        var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.SetMinimumLevel(LogLevel.Warning);
        });

        var logger = loggerFactory.CreateLogger<ImageCreationStuff>();
        var imageCreatorLogger = loggerFactory.CreateLogger<ImageCreatorSharp>();

        _picSettings = new PicSettings
        {
            DirectorySorgente = _sourceDirectory,
            DirectoryDestinazione = _destinationDirectory,
            DimStandard = 800,
            DimStandardMiniatura = 200,
            LarghezzaBig = 1024,
            AltezzaBig = 768,
            LarghezzaSmall = 200,
            AltezzaSmall = 150,
            CreaMiniature = true,
            AggiungiScritteMiniature = false,
            UsaForzaJpg = true,
            UsaRotazioneAutomatica = true,
            LogoAggiungi = false,
            FotoGrandeDimOrigina = false,
            TestoNome = false,
            NomeData = false,
            Suffisso = "_small",
            Margine = 10,
            Trasparenza = 100
        };

        var imageCreatorService = new ImageCreatorSharp(_picSettings, imageCreatorLogger);
        _imageCreationStuff = new ImageCreationStuff(logger, _picSettings, imageCreatorService);

        Console.WriteLine($"[STRESS TEST] Setup complete. Ready to process {ImageCount} images.");
    }

    [GlobalCleanup]
    public void Cleanup()
    {
        Console.WriteLine("[STRESS TEST] Cleaning up test data...");
        try
        {
            var tempBase = Path.GetDirectoryName(_sourceDirectory);
            if (Directory.Exists(tempBase))
            {
                Directory.Delete(tempBase, recursive: true);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Cleanup error: {ex.Message}");
        }
    }

    [IterationSetup]
    public void IterationSetup()
    {
        if (Directory.Exists(_destinationDirectory))
        {
            Directory.Delete(_destinationDirectory, recursive: true);
        }
        Directory.CreateDirectory(_destinationDirectory);
        GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, blocking: true, compacting: true);
    }

    [Benchmark(Description = "Stress test with optimal settings")]
    public async Task StressTestOptimalSettings()
    {
        var options = new ImageCreationStuff.Options
        {
            SourcePath = _sourceDirectory,
            DestinationPath = _destinationDirectory,
            MaxThreads = Environment.ProcessorCount,
            ChunksSize = 25, // Process in chunks to manage memory
            LinearExecution = false,
            AggiornaSottodirectory = false,
            CreaSottocartelle = false,
            FilePerCartella = 100,
            SuffissoCartelle = "",
            CifreContatore = 4,
            NumerazioneType = NumerazioneType.Progressiva
        };

        var results = new ConcurrentBag<string>();
        var startTime = DateTime.Now;
        
        await _imageCreationStuff.ProcessImagesParallel(options, results, null, CancellationToken.None);
        
        var duration = DateTime.Now - startTime;
        var throughput = ImageCount / duration.TotalSeconds;
        
        Console.WriteLine($"[STRESS TEST] Processed {results.Count}/{ImageCount} images in {duration.TotalSeconds:F2}s");
        Console.WriteLine($"[STRESS TEST] Throughput: {throughput:F2} images/second");
    }

    [Benchmark(Description = "Stress test with aggressive memory management")]
    public async Task StressTestAggressiveMemoryManagement()
    {
        var options = new ImageCreationStuff.Options
        {
            SourcePath = _sourceDirectory,
            DestinationPath = _destinationDirectory,
            MaxThreads = Environment.ProcessorCount / 2, // Reduce threads to save memory
            ChunksSize = 10, // Smaller chunks for more frequent GC
            LinearExecution = false,
            AggiornaSottodirectory = false,
            CreaSottocartelle = false,
            FilePerCartella = 100,
            SuffissoCartelle = "",
            CifreContatore = 4,
            NumerazioneType = NumerazioneType.Progressiva
        };

        var results = new ConcurrentBag<string>();
        var startTime = DateTime.Now;
        
        await _imageCreationStuff.ProcessImagesParallel(options, results, null, CancellationToken.None);
        
        var duration = DateTime.Now - startTime;
        var throughput = ImageCount / duration.TotalSeconds;
        
        Console.WriteLine($"[STRESS TEST] Processed {results.Count}/{ImageCount} images in {duration.TotalSeconds:F2}s");
        Console.WriteLine($"[STRESS TEST] Throughput: {throughput:F2} images/second");
    }
}
