using ImageCatalog_2.Commands;
using ImageCatalog_2.Services;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
using AutoMapper;
using MaddoShared;
using Microsoft.Extensions.Logging;

namespace ImageCatalog_2
{
    public class DataModel : ViewModelBase
    {
        public ICommand TestCommand { get; }
        public ICommand AsyncTestCommand { get; }
        public ICommand AsyncCancelOperationCommand { get; }
        public ICommand ProcessImagesCommand { get; }
        public ICommand SelectSourceFolderCommand { get; }
        public ICommand SelectDestinationFolderCommand { get; }
        public ICommand SelectLogoFileCommand { get; }
        public ICommand SaveSettingsCommand { get; }
        public ICommand LoadSettingsCommand { get; }
        public ICommand SelectColorCommand { get; }
        public ICommand SelectTransparentColorCommand { get; }
        public ICommand SelectModelsFolderCommand { get; }
        public ICommand SelectCsvOutputCommand { get; }

        private readonly ITestService _service;
        private readonly ILogger<DataModel> _logger;
        private readonly ISettingsService _settingsService;
        private readonly ImageCreationStuff _imageCreationService;
        private readonly PicSettings _picSettings;
        private readonly IMapper _mapper;

        // ComboBox collections
        public List<string> AvailableFonts { get; }
        public List<string> VerticalPositions { get; } = new() { "Alto", "Centro", "Basso" };
        public List<string> HorizontalAlignments { get; } = new() { "Sinistra", "Centro", "Destra" };

        public DataModel(ITestService testService, ISettingsService settingsService, 
            ImageCreationStuff imageCreationService, PicSettings picSettings, 
            IMapper mapper, ILogger<DataModel> logger, MaddoShared.IVersionProvider? versionProvider = null)
        {
            _service = testService;
            _logger = logger;
            _settingsService = settingsService;
            _imageCreationService = imageCreationService;
            _picSettings = picSettings;
            _mapper = mapper;
            // Populate AppVersion from version provider when available
            AppVersion = versionProvider?.GetVersionString() ?? string.Empty;

            TestCommand = new RelayCommand(Test);
            AsyncTestCommand = new AsyncCommand(TestAsync);
            AsyncCancelOperationCommand = new AsyncCommand(CancelOperation);
            ProcessImagesCommand = new AsyncCommand(ProcessImages);
            SelectModelsFolderCommand = new RelayCommand(SelectModelsFolder);
            SelectCsvOutputCommand = new RelayCommand(SelectCsvOutput);
            
            SelectSourceFolderCommand = new RelayCommand(SelectSourceFolder);
            SelectDestinationFolderCommand = new RelayCommand(SelectDestinationFolder);
            SelectLogoFileCommand = new RelayCommand(SelectLogoFile);
            SaveSettingsCommand = new RelayCommand(SaveSettings);
            LoadSettingsCommand = new RelayCommand(LoadSettings);
            SelectColorCommand = new RelayCommand(SelectColor);
            SelectTransparentColorCommand = new RelayCommand(SelectTransparentColor);

            // Load available fonts
            AvailableFonts = LoadAvailableFonts();
        }

        private async Task RunAiExtractionAsync(CancellationToken token)
        {
            // Simple stub: scan source folder for supported images and either call AIFotoONLUS.Core
            // or simulate results. Write CSV output and populate PreviewResults.
            if (string.IsNullOrWhiteSpace(SourcePath) || !System.IO.Directory.Exists(SourcePath))
            {
                _logger.LogWarning("Source path invalid for AI extraction: {SourcePath}", SourcePath);
                return;
            }

            var imageFiles = System.IO.Directory.EnumerateFiles(SourcePath, "*.*", System.IO.SearchOption.TopDirectoryOnly)
                .Where(f => f.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)
                         || f.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)
                         || f.EndsWith(".png", StringComparison.OrdinalIgnoreCase)
                         || f.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase)
                         || f.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
                .ToList();

            if (imageFiles.Count == 0)
            {
                _logger.LogInformation("No image files found for AI extraction in {SourcePath}", SourcePath);
                return;
            }

            // Clear preview
            await InvokeOnUiThreadAsync(() => { PreviewResults.Clear(); });

            // Try to locate AIFotoONLUS.Core types via reflection to avoid hard reference at compile time
            Type? aiProcessorType = null;
            object? aiProcessor = null;

            try
            {
                var assembly = AppDomain.CurrentDomain.GetAssemblies()
                    .FirstOrDefault(a => a.GetName().Name?.Equals("AIFotoONLUS.Core", StringComparison.OrdinalIgnoreCase) == true);
                if (assembly != null)
                {
                    aiProcessorType = assembly.GetType("AIFotoONLUS.Core.AiProcessor");
                    if (aiProcessorType != null)
                    {
                        // Create instance assuming parameterless ctor
                        aiProcessor = Activator.CreateInstance(aiProcessorType);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogDebug(ex, "AIFotoONLUS.Core not available or failed to load via reflection");
            }

            var results = new List<AiResult>();

            foreach (var file in imageFiles)
            {
                token.ThrowIfCancellationRequested();

                string extracted = string.Empty;

                if (aiProcessorType is not null && aiProcessor is not null)
                {
                    try
                    {
                        // Preferred method name: ExtractNumbersFromImage(string imagePath)
                        var method = aiProcessorType.GetMethod("ExtractNumbersFromImage") ?? aiProcessorType.GetMethod("ExtractTextFromImage");
                        if (method is not null)
                        {
                            var value = method.Invoke(aiProcessor, new object[] { file });
                            if (value != null)
                                extracted = value.ToString() ?? string.Empty;
                        }
                        else
                        {
                            // No expected method found, fallback to simulated result
                            extracted = SimulateExtraction(file);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Error invoking AI processor for {File}", file);
                        extracted = SimulateExtraction(file);
                    }
                }
                else
                {
                    // Simulate extraction when library not available
                    extracted = SimulateExtraction(file);
                }

                var res = new AiResult { Path = file, Text = extracted };
                results.Add(res);

                await InvokeOnUiThreadAsync(() => PreviewResults.Add(res));
            }

            // Write CSV if requested
            if (!string.IsNullOrWhiteSpace(CsvOutputPath))
            {
                try
                {
                    var dir = System.IO.Path.GetDirectoryName(CsvOutputPath) ?? string.Empty;
                    if (!string.IsNullOrWhiteSpace(dir) && !System.IO.Directory.Exists(dir))
                    {
                        System.IO.Directory.CreateDirectory(dir);
                    }

                    using var sw = new System.IO.StreamWriter(CsvOutputPath, false, System.Text.Encoding.UTF8);
                    sw.WriteLine("Path,Text");
                    foreach (var r in results)
                    {
                        var safeText = (r.Text ?? string.Empty).Replace("\"", "\"\"");
                        sw.WriteLine($"\"{r.Path}\",\"{safeText}\"");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Failed to write CSV to {CsvOutputPath}", CsvOutputPath);
                }
            }
        }

        private string SimulateExtraction(string file)
        {
            // Cheap heuristic: return filename digits
            var name = System.IO.Path.GetFileNameWithoutExtension(file);
            var digits = new string(name.Where(char.IsDigit).ToArray());
            if (string.IsNullOrEmpty(digits)) return "";
            return digits;
        }

        private Task InvokeOnUiThreadAsync(Action action)
        {
            // Use SynchronizationContext via Task to ensure UI thread update
            return Task.Run(() =>
            {
                System.Windows.Application.Current?.Dispatcher.Invoke(action);
            });
        }

        // AI properties
        private bool _extractNumbers;
        public bool ExtractNumbers
        {
            get => _extractNumbers;
            set { _extractNumbers = value; NotifyPropertyChanged(); }
        }

        private string _modelsFolderPath = string.Empty;
        public string ModelsFolderPath
        {
            get => _modelsFolderPath;
            set { _modelsFolderPath = value; NotifyPropertyChanged(); }
        }

        private string _csvOutputPath = string.Empty;
        public string CsvOutputPath
        {
            get => _csvOutputPath;
            set { _csvOutputPath = value; NotifyPropertyChanged(); }
        }

        // Preview results for DataGrid
        private System.Collections.ObjectModel.ObservableCollection<AiResult> _previewResults = new();
        public System.Collections.ObjectModel.ObservableCollection<AiResult> PreviewResults => _previewResults;

        public class AiResult
        {
            public string Path { get; set; } = string.Empty;
            public string Text { get; set; } = string.Empty;
        }

        private List<string> LoadAvailableFonts()
        {
            var fonts = new List<string>();
            using (var installedFonts = new InstalledFontCollection())
            {
                fonts.AddRange(installedFonts.Families.Select(f => f.Name));
            }
            return fonts;
        }

        private CancellationTokenSource? _mainToken;

        public CancellationTokenSource? MainToken
        {
            get => _mainToken;
            set
            {
                _mainToken = value;
                NotifyPropertyChanged();
            }
        }

        private string _sourcePath;

        public string SourcePath
        {
            get => _sourcePath;
            set
            {
                _sourcePath = value;
                NotifyPropertyChanged();
            }
        }

        private string _destinationPath;

        public string DestinationPath
        {
            get => _destinationPath;
            set
            {
                _destinationPath = value;
                NotifyPropertyChanged();
            }
        }

        private string _horizontalText;

        public string HorizontalText
        {
            get => _horizontalText;
            set
            {
                _horizontalText = value;
                NotifyPropertyChanged();
            }
        }

        private string _verticalText;

        public string VerticalText
        {
            get => _verticalText;
            set
            {
                _verticalText = value;
                NotifyPropertyChanged();
            }
        }

        private bool _overwriteImages;

        public bool OverwriteImages
        {
            get => _overwriteImages;
            set
            {
                _overwriteImages = value;
                NotifyPropertyChanged();
            }
        }

        private bool _uiEnabled = true;

        public bool UiEnabled
        {
            get => _uiEnabled;
            set
            {
                _uiEnabled = value;
                NotifyPropertyChanged();
                NotifyPropertyChanged(nameof(UiDisabled));
            }
        }

        public bool UiDisabled => !_uiEnabled;

        private string _speedCounter = "-";

        public string SpeedCounter
        {
            get => _speedCounter;
            set
            {
                _speedCounter = value;
                NotifyPropertyChanged();
            }
        }

        private int _chunkSize;

        public int ChunkSize
        {
            get => _chunkSize;
            set
            {
                _chunkSize = value;
                NotifyPropertyChanged();
            }
        }

        private int _threadsCount;

        public int ThreadsCount
        {
            get => _threadsCount;
            set
            {
                _threadsCount = value;
                NotifyPropertyChanged();
            }
        }

        // Thumbnail settings
        private string _thumbnailPrefix = "tn_";
        public string ThumbnailPrefix
        {
            get => _thumbnailPrefix;
            set
            {
                _thumbnailPrefix = value;
                NotifyPropertyChanged();
            }
        }

        private int _thumbnailHeight = 350;
        public int ThumbnailHeight
        {
            get => _thumbnailHeight;
            set
            {
                _thumbnailHeight = value;
                NotifyPropertyChanged();
            }
        }

        private int _thumbnailWidth = 350;
        public int ThumbnailWidth
        {
            get => _thumbnailWidth;
            set
            {
                _thumbnailWidth = value;
                NotifyPropertyChanged();
            }
        }

        // Big photo settings
        private int _photoBigHeight = 2240;
        public int PhotoBigHeight
        {
            get => _photoBigHeight;
            set
            {
                _photoBigHeight = value;
                NotifyPropertyChanged();
            }
        }

        private int _photoBigWidth = 2240;
        public int PhotoBigWidth
        {
            get => _photoBigWidth;
            set
            {
                _photoBigWidth = value;
                NotifyPropertyChanged();
            }
        }

        // Font settings
        private int _fontSize = 20;
        public int FontSize
        {
            get => _fontSize;
            set
            {
                _fontSize = value;
                NotifyPropertyChanged();
            }
        }

        private int _fontSizeThumbnail = 50;
        public int FontSizeThumbnail
        {
            get => _fontSizeThumbnail;
            set
            {
                _fontSizeThumbnail = value;
                NotifyPropertyChanged();
            }
        }

        private string _fontName = "Arial";
        public string FontName
        {
            get => _fontName;
            set
            {
                _fontName = value;
                NotifyPropertyChanged();
            }
        }

        private bool _fontBold = false;
        public bool FontBold
        {
            get => _fontBold;
            set
            {
                _fontBold = value;
                NotifyPropertyChanged();
            }
        }

        // Text settings
        private int _textTransparency = 0;
        public int TextTransparency
        {
            get => _textTransparency;
            set
            {
                _textTransparency = value;
                NotifyPropertyChanged();
            }
        }

        private int _textMargin = 8;
        public int TextMargin
        {
            get => _textMargin;
            set
            {
                _textMargin = value;
                NotifyPropertyChanged();
            }
        }

        private string _textColorRGB = "Yellow";
        public string TextColorRGB
        {
            get => _textColorRGB;
            set
            {
                _textColorRGB = value;
                NotifyPropertyChanged();
            }
        }

        private string _transparentColor = "#FFFFFF";
        public string TransparentColor
        {
            get => _transparentColor;
            set
            {
                _transparentColor = value;
                NotifyPropertyChanged();
            }
        }

        private bool _useTransparentColor;
        public bool UseTransparentColor
        {
            get => _useTransparentColor;
            set
            {
                _useTransparentColor = value;
                NotifyPropertyChanged();
            }
        }

        // Logo/Watermark settings
        private string _logoFile = "";
        public string LogoFile
        {
            get => _logoFile;
            set
            {
                _logoFile = value;
                NotifyPropertyChanged();
            }
        }

        private int _logoHeight = 430;
        public int LogoHeight
        {
            get => _logoHeight;
            set
            {
                _logoHeight = value;
                NotifyPropertyChanged();
            }
        }

        private int _logoWidth = 430;
        public int LogoWidth
        {
            get => _logoWidth;
            set
            {
                _logoWidth = value;
                NotifyPropertyChanged();
            }
        }

        private int _logoMargin = 290;
        public int LogoMargin
        {
            get => _logoMargin;
            set
            {
                _logoMargin = value;
                NotifyPropertyChanged();
            }
        }

        private int _logoTransparency = 100;
        public int LogoTransparency
        {
            get => _logoTransparency;
            set
            {
                _logoTransparency = value;
                NotifyPropertyChanged();
            }
        }

        // Image library selection (UI radio buttons bind to the boolean helpers)
        private string _imageLibrary = "System.Graphics";

        /// <summary>
        /// The selected image processing library. Possible values: "System.Graphics" or "ImageSharp".
        /// This value is mirrored into PicSettings.ImageCreatorProvider so the runtime mapper picks the implementation.
        /// </summary>
        public string ImageLibrary
        {
            get => _imageLibrary;
            set
            {
                if (_imageLibrary == value) return;
                _imageLibrary = value;
                // Reflect selection into PicSettings so mapper can resolve at runtime
                _picSettings.ImageCreatorProvider = string.Equals(value, "ImageSharp", StringComparison.OrdinalIgnoreCase)
                    ? "ALTERNATE"
                    : "Sharp";
                NotifyPropertyChanged();
                NotifyPropertyChanged(nameof(UseSystemGraphics));
                NotifyPropertyChanged(nameof(UseImageSharp));
            }
        }

        public bool UseSystemGraphics
        {
            get => string.Equals(ImageLibrary, "System.Graphics", StringComparison.OrdinalIgnoreCase);
            set
            {
                if (value) ImageLibrary = "System.Graphics";
                NotifyPropertyChanged();
            }
        }

        public bool UseImageSharp
        {
            get => string.Equals(ImageLibrary, "ImageSharp", StringComparison.OrdinalIgnoreCase);
            set
            {
                if (value) ImageLibrary = "ImageSharp";
                NotifyPropertyChanged();
            }
        }

        // Folder division settings
        private int _filesPerFolder = 99;
        public int FilesPerFolder
        {
            get => _filesPerFolder;
            set
            {
                _filesPerFolder = value;
                NotifyPropertyChanged();
            }
        }

        private string _folderSuffix = "";
        public string FolderSuffix
        {
            get => _folderSuffix;
            set
            {
                _folderSuffix = value;
                NotifyPropertyChanged();
            }
        }

        private int _counterDigits = 2;
        public int CounterDigits
        {
            get => _counterDigits;
            set
            {
                _counterDigits = value;
                NotifyPropertyChanged();
            }
        }

        // Vertical text settings
        private int _verticalTextSize = 20;
        public int VerticalTextSize
        {
            get => _verticalTextSize;
            set
            {
                _verticalTextSize = value;
                NotifyPropertyChanged();
            }
        }

        private int _verticalTextMargin = 6;
        public int VerticalTextMargin
        {
            get => _verticalTextMargin;
            set
            {
                _verticalTextMargin = value;
                NotifyPropertyChanged();
            }
        }

        // JPEG compression settings
        private int _jpegQuality = 85;
        public int JpegQuality
        {
            get => _jpegQuality;
            set
            {
                _jpegQuality = value;
                NotifyPropertyChanged();
            }
        }

        private int _jpegQualityThumbnail = 30;
        public int JpegQualityThumbnail
        {
            get => _jpegQualityThumbnail;
            set
            {
                _jpegQualityThumbnail = value;
                NotifyPropertyChanged();
            }
        }

        // CheckBox settings
        private bool _createThumbnails = true;
        public bool CreateThumbnails
        {
            get => _createThumbnails;
            set
            {
                _createThumbnails = value;
                NotifyPropertyChanged();
            }
        }

        private bool _automaticRotation;
        public bool AutomaticRotation
        {
            get => _automaticRotation;
            set
            {
                _automaticRotation = value;
                NotifyPropertyChanged();
            }
        }

        private bool _forceJpeg;
        public bool ForceJpeg
        {
            get => _forceJpeg;
            set
            {
                _forceJpeg = value;
                NotifyPropertyChanged();
            }
        }

        private bool _updateSubdirectories;
        public bool UpdateSubdirectories
        {
            get => _updateSubdirectories;
            set
            {
                _updateSubdirectories = value;
                NotifyPropertyChanged();
            }
        }

        private bool _createSubfolders;
        public bool CreateSubfolders
        {
            get => _createSubfolders;
            set
            {
                _createSubfolders = value;
                NotifyPropertyChanged();
            }
        }

        private bool _addTime;
        public bool AddTime
        {
            get => _addTime;
            set
            {
                _addTime = value;
                NotifyPropertyChanged();
            }
        }

        private bool _addRaceTime;
        public bool AddRaceTime
        {
            get => _addRaceTime;
            set
            {
                _addRaceTime = value;
                NotifyPropertyChanged();
            }
        }

        private bool _addLogo;
        public bool AddLogo
        {
            get => _addLogo;
            set
            {
                _addLogo = value;
                NotifyPropertyChanged();
            }
        }

        private bool _keepOriginalDimensions;
        public bool KeepOriginalDimensions
        {
            get => _keepOriginalDimensions;
            set
            {
                _keepOriginalDimensions = value;
                NotifyPropertyChanged();
            }
        }

        private bool _showDate;
        public bool ShowDate
        {
            get => _showDate;
            set
            {
                _showDate = value;
                NotifyPropertyChanged();
            }
        }

        private bool _showPhotoNumber;
        public bool ShowPhotoNumber
        {
            get => _showPhotoNumber;
            set
            {
                if (_showPhotoNumber == value) return;
                _showPhotoNumber = value;
                if (value)
                {
                    // ensure mutually exclusive choices
                    _addTimeToThumbnails = false;
                    _addTextToThumbnails = false;
                    _addNumberAndTimeToThumbnails = false;
                    _addRaceTimeToThumbnails = false;
                    NotifyPropertyChanged(nameof(AddTimeToThumbnails));
                    NotifyPropertyChanged(nameof(AddTextToThumbnails));
                    NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails));
                    NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails));
                }
                NotifyPropertyChanged();
                NotifyPropertyChanged(nameof(ThumbnailMode));
            }
        }

        private bool _shutdownSystem;
        public bool ShutdownSystem
        {
            get => _shutdownSystem;
            set
            {
                _shutdownSystem = value;
                NotifyPropertyChanged();
            }
        }

        // ComboBox position/alignment settings
        private string _verticalPosition = "Basso";
        public string VerticalPosition
        {
            get => _verticalPosition;
            set
            {
                _verticalPosition = value;
                NotifyPropertyChanged();
            }
        }

        private string _horizontalAlignment = "Centro";
        public string HorizontalAlignment
        {
            get => _horizontalAlignment;
            set
            {
                _horizontalAlignment = value;
                NotifyPropertyChanged();
            }
        }

        private string _logoHorizontalPosition = "Destra";
        public string LogoHorizontalPosition
        {
            get => _logoHorizontalPosition;
            set
            {
                _logoHorizontalPosition = value;
                NotifyPropertyChanged();
            }
        }

        private string _logoVerticalPosition = "Basso";
        public string LogoVerticalPosition
        {
            get => _logoVerticalPosition;
            set
            {
                _logoVerticalPosition = value;
                NotifyPropertyChanged();
            }
        }

        // RadioButton settings
        private bool _useProgressiveNumbering = true;
        public bool UseProgressiveNumbering
        {
            get => _useProgressiveNumbering;
            set
            {
                _useProgressiveNumbering = value;
                NotifyPropertyChanged();
            }
        }

        private bool _useFileNumbering;
        public bool UseFileNumbering
        {
            get => _useFileNumbering;
            set
            {
                _useFileNumbering = value;
                NotifyPropertyChanged();
            }
        }

        private bool _useParallelProcessing = true;
        public bool UseParallelProcessing
        {
            get => _useParallelProcessing;
            set
            {
                _useParallelProcessing = value;
                NotifyPropertyChanged();
            }
        }

        private bool _useSequentialProcessing;
        public bool UseSequentialProcessing
        {
            get => _useSequentialProcessing;
            set
            {
                _useSequentialProcessing = value;
                NotifyPropertyChanged();
            }
        }

        // Additional settings that were missing
        private bool _addTimeToThumbnails;
        public bool AddTimeToThumbnails
        {
            get => _thumbnailOption == ThumbnailOptionEnum.Time;
            set
            {
                if (value)
                {
                    ThumbnailOption = ThumbnailOptionEnum.Time;
                }
                else if (_thumbnailOption == ThumbnailOptionEnum.Time)
                {
                    ThumbnailOption = ThumbnailOptionEnum.None;
                }
                NotifyPropertyChanged();
            }
        }

        private bool _showFileNameOnThumbnails;
        public bool ShowFileNameOnThumbnails
        {
            get => _thumbnailOption == ThumbnailOptionEnum.FileName;
            set
            {
                if (value)
                    ThumbnailOption = ThumbnailOptionEnum.FileName;
                else if (_thumbnailOption == ThumbnailOptionEnum.FileName)
                    ThumbnailOption = ThumbnailOptionEnum.None;
                NotifyPropertyChanged();
            }
        }

        private DateTime _raceStartDate = DateTime.Now;
        public DateTime RaceStartDate
        {
            get => _raceStartDate;
            set
            {
                _raceStartDate = value;
                NotifyPropertyChanged();
            }
        }

        private string _timeLabel = "";
        public string TimeLabel
        {
            get => _timeLabel;
            set
            {
                _timeLabel = value;
                NotifyPropertyChanged();
            }
        }

        private string _bigPhotoSuffix = "";
        public string BigPhotoSuffix
        {
            get => _bigPhotoSuffix;
            set
            {
                _bigPhotoSuffix = value;
                NotifyPropertyChanged();
            }
        }

        private bool _addTextToThumbnails;
        public bool AddTextToThumbnails
        {
            get => _thumbnailOption == ThumbnailOptionEnum.Text;
            set
            {
                if (value)
                    ThumbnailOption = ThumbnailOptionEnum.Text;
                else if (_thumbnailOption == ThumbnailOptionEnum.Text)
                    ThumbnailOption = ThumbnailOptionEnum.None;
                NotifyPropertyChanged();
            }
        }

        private bool _addRaceTimeToThumbnails;
        public bool AddRaceTimeToThumbnails
        {
            get => _thumbnailOption == ThumbnailOptionEnum.RaceTime;
            set
            {
                if (value)
                    ThumbnailOption = ThumbnailOptionEnum.RaceTime;
                else if (_thumbnailOption == ThumbnailOptionEnum.RaceTime)
                    ThumbnailOption = ThumbnailOptionEnum.None;
                NotifyPropertyChanged();
            }
        }

        private bool _addNumberAndTimeToThumbnails;
        public bool AddNumberAndTimeToThumbnails
        {
            get => _thumbnailOption == ThumbnailOptionEnum.FileNameAndTime;
            set
            {
                if (value)
                    ThumbnailOption = ThumbnailOptionEnum.FileNameAndTime;
                else if (_thumbnailOption == ThumbnailOptionEnum.FileNameAndTime)
                    ThumbnailOption = ThumbnailOptionEnum.None;
                NotifyPropertyChanged();
            }
        }

        // New enum and authoritative property for thumbnail selection
        public enum ThumbnailOptionEnum
        {
            None = 0,
            Text = 1,
            FileName = 2,
            Time = 3,
            FileNameAndTime = 4,
            RaceTime = 5
        }

        private ThumbnailOptionEnum _thumbnailOption = ThumbnailOptionEnum.None;

        // Name matches DTO property so SettingsService mapping works
        public ThumbnailOptionEnum ThumbnailOption
        {
            get => _thumbnailOption;
            set
            {
                if (_thumbnailOption == value) return;
                _thumbnailOption = value;
                // Notify all dependent properties so UI updates
                NotifyPropertyChanged();
                NotifyPropertyChanged(nameof(AddTextToThumbnails));
                NotifyPropertyChanged(nameof(AddTimeToThumbnails));
                NotifyPropertyChanged(nameof(ShowPhotoNumber));
                NotifyPropertyChanged(nameof(AddNumberAndTimeToThumbnails));
                NotifyPropertyChanged(nameof(AddRaceTimeToThumbnails));
                NotifyPropertyChanged(nameof(ShowFileNameOnThumbnails));
                NotifyPropertyChanged(nameof(ThumbnailMode));
            }
        }

        // Helper int property to bind ComboBox SelectedIndex in the WinForms designer
        public int ThumbnailOptionIndex
        {
            get => (int)ThumbnailOption;
            set
            {
                var opt = (ThumbnailOptionEnum)value;
                if (opt == ThumbnailOption) return;
                ThumbnailOption = opt;
                NotifyPropertyChanged();
            }
        }

        // Single authoritative thumbnail mode string to avoid conflicting bindings
        // Possible values: "None", "Text", "Time", "Number", "NumberAndTime", "RaceTime"
        public string ThumbnailMode
        {
            get
            {
                return _thumbnailOption switch
                {
                    ThumbnailOptionEnum.Text => "Text",
                    ThumbnailOptionEnum.Time => "Time",
                    ThumbnailOptionEnum.FileName => "Number",
                    ThumbnailOptionEnum.FileNameAndTime => "NumberAndTime",
                    ThumbnailOptionEnum.RaceTime => "RaceTime",
                    _ => "None",
                };
            }
            set
            {
                // Map incoming string to enum and set the authoritative property
                switch ((value ?? string.Empty).ToLowerInvariant())
                {
                    case "text":
                        ThumbnailOption = ThumbnailOptionEnum.Text;
                        break;
                    case "time":
                        ThumbnailOption = ThumbnailOptionEnum.Time;
                        break;
                    case "number":
                        ThumbnailOption = ThumbnailOptionEnum.FileName;
                        break;
                    case "numberandtime":
                        ThumbnailOption = ThumbnailOptionEnum.FileNameAndTime;
                        break;
                    case "racetime":
                        ThumbnailOption = ThumbnailOptionEnum.RaceTime;
                        break;
                    default:
                        ThumbnailOption = ThumbnailOptionEnum.None;
                        break;
                }
            }
        }

        // Image processing progress and status
        private string _processingStatus = "";
        public string ProcessingStatus
        {
            get => _processingStatus;
            set
            {
                _processingStatus = value;
                NotifyPropertyChanged();
            }
        }

        private int _processedImagesCount = 0;
        public int ProcessedImagesCount
        {
            get => _processedImagesCount;
            set
            {
                _processedImagesCount = value;
                NotifyPropertyChanged();
            }
        }

        private int _totalImagesCount = 0;
        public int TotalImagesCount
        {
            get => _totalImagesCount;
            set
            {
                _totalImagesCount = value;
                NotifyPropertyChanged();
            }
        }

        private int _progressBarValue = 0;
        public int ProgressBarValue
        {
            get => _progressBarValue;
            set
            {
                _progressBarValue = value;
                NotifyPropertyChanged();
            }
        }

        private int _progressBarMaximum = 100;
        public int ProgressBarMaximum
        {
            get => _progressBarMaximum;
            set
            {
                _progressBarMaximum = value;
                NotifyPropertyChanged();
            }
        }

        private ConcurrentBag<string> _results = new();
        private int _currentAmount = 0;
        private int _previousAmount = 0;
        // Atomic counter for processed images — avoids expensive ConcurrentBag.Count enumerations
        private int _processedAtomic = 0;
        private System.Threading.Timer? _speedTimer;
        // Stopwatch used to compute run-wide averages
        private Stopwatch? _speedWatch;
        // Recent diffs queue to smooth short-term fluctuations
        private readonly Queue<int> _recentDiffs = new();
        private int _recentWindowSize = 5; // average over last 5 samples (~5s)

        private void Test(object parameter)
        {
            Debug.WriteLine("Yep");
            this.UiEnabled = !this.UiEnabled;
        }

        private async Task TestAsync()
        {
            Debug.WriteLine("Yep c");
        }

        private async Task ProcessImages()
        {
            _logger.LogInformation("Avvio elaborazione...");
            UiEnabled = false;

            MainToken?.Dispose();
            MainToken = new CancellationTokenSource();
            var token = MainToken.Token;

            // Fix paths
            FixPaths();
            
            // Reset counters
            ProcessingStatus = "Elaborazione in corso...";
            TotalImagesCount = 0;
            ProcessedImagesCount = 0;
            SpeedCounter = "-f/s";
            ProgressBarValue = 0;
            ProgressBarMaximum = 100;
            
            // Update PicSettings from DataModel using AutoMapper
            _mapper.Map(this, _picSettings);
            // Explicitly ensure thumbnail-related flags are applied to PicSettings
            // because AutoMapper may not map differently-named properties.
            try
            {
                _picSettings.AggiungiScritteMiniature = this.AddTextToThumbnails;
                _picSettings.UsaOrarioMiniatura = this.AddTimeToThumbnails;
                _picSettings.AggNumTempMin = this.AddNumberAndTimeToThumbnails;
                _picSettings.AggTempoGaraMin = this.AddRaceTimeToThumbnails;
                _picSettings.CreaMiniature = this.CreateThumbnails;
                _picSettings.LarghezzaSmall = this.ThumbnailWidth;
                _picSettings.AltezzaSmall = this.ThumbnailHeight;
                _picSettings.DimMin = this.FontSizeThumbnail;
                _picSettings.JpegQualityMin = this.JpegQualityThumbnail;
            }
            catch
            {
                // Best-effort; do not fail processing on mapping issues
            }
            
            var imageCreationOptions = new ImageCreationStuff.Options
            {
                AggiornaSottodirectory = UpdateSubdirectories,
                CreaSottocartelle = CreateSubfolders,
                FilePerCartella = FilesPerFolder,
                SuffissoCartelle = FolderSuffix,
                CifreContatore = CounterDigits,
                NumerazioneType = UseProgressiveNumbering ? NumerazioneType.Progressiva : NumerazioneType.Files,
                SourcePath = SourcePath,
                DestinationPath = DestinationPath,
                MaxThreads = ThreadsCount,
                ChunksSize = ChunkSize,
                LinearExecution = UseSequentialProcessing
            };

            try
            {
                _results = new ConcurrentBag<string>();
                _currentAmount = 0;
                _previousAmount = 0;
                _processedAtomic = 0;
                
                // Start speed timer (sample every second using lightweight atomic reads)
                _speedWatch = Stopwatch.StartNew();
                _recentDiffs.Clear();
                _speedTimer = new System.Threading.Timer(UpdateSpeedCounter, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));

                var time = await _imageCreationService.CreaCatalogoParallel(
                    imageCreationOptions, 
                    _results, 
                    OnImageProcessed, 
                    token);

                // AI integration stub: if ExtractNumbers is enabled, simulate or invoke OCR processing
                if (ExtractNumbers)
                {
                    try
                    {
                        await RunAiExtractionAsync(token);
                    }
                    catch (OperationCanceledException)
                    {
                        _logger.LogInformation("AI extraction canceled");
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "AI extraction failed");
                    }
                }
                    
                // Compute final averages and show only averages (do not show raw seconds)
                var finalProcessed = System.Threading.Volatile.Read(ref _processedAtomic);
                double overallAvg = 0.0;
                double overallPerMin = 0.0;
                if (_speedWatch is not null && _speedWatch.Elapsed.TotalSeconds > 0.0)
                {
                    overallAvg = finalProcessed / _speedWatch.Elapsed.TotalSeconds;
                    overallPerMin = overallAvg * 60.0;
                }

                // Compute elapsed time as h m s and show final averages (no raw seconds parentheses)
                var finalElapsed = _speedWatch?.Elapsed ?? TimeSpan.Zero;
                int fh = (int)finalElapsed.TotalHours;
                int fm = finalElapsed.Minutes;
                int fs = finalElapsed.Seconds;

                SpeedCounter = $"{fh}h {fm}m {fs}s{Environment.NewLine}media: {overallAvg:0.00} f/s{Environment.NewLine}media: {overallPerMin:0.00} f/m";

                _speedTimer?.Dispose();
                _speedTimer = null;
                _speedWatch?.Stop();
                _speedWatch = null;
            }
            catch (OperationCanceledException)
            {
                _logger.LogInformation("Operazione Cancellata");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Errore durante l'elaborazione delle immagini");
                ProcessingStatus = $"Errore: {ex.Message}";
            }
            finally
            {
                MainToken?.Dispose();
                MainToken = null;
                _speedTimer?.Dispose();
                _speedTimer = null;
            }

            ProcessingStatus = "Finito";
            UiEnabled = true;
        }

        private void UpdateSpeedCounter(object? state)
        {
            try
            {
                _previousAmount = _currentAmount;
                // Read the atomic counter without enumerating the ConcurrentBag
                _currentAmount = System.Threading.Volatile.Read(ref _processedAtomic);
                int diff = _currentAmount - _previousAmount;

                // Protect against negative or spurious diffs
                if (diff < 0) diff = 0;

                // Maintain a small sliding window of recent diffs to smooth the display
                lock (_recentDiffs)
                {
                    _recentDiffs.Enqueue(diff);
                    if (_recentDiffs.Count > _recentWindowSize)
                        _recentDiffs.Dequeue();
                }

                double avgRecent;
                lock (_recentDiffs)
                {
                    avgRecent = _recentDiffs.Count == 0 ? 0.0 : _recentDiffs.Average();
                }

                // Compute overall average (since start) if we have a stopwatch
                double overall = 0.0;
                if (_speedWatch is not null && _speedWatch.Elapsed.TotalSeconds >= 1)
                {
                    var elapsedSeconds = _speedWatch.Elapsed.TotalSeconds;
                    var total = System.Threading.Volatile.Read(ref _processedAtomic);
                    overall = elapsedSeconds > 0 ? total / elapsedSeconds : 0.0;
                }

                // Recent per-minute estimate
                var recentPerMin = avgRecent * 60.0;
                var overallPerMin = overall * 60.0;

                // Build a two-line display plus elapsed time: first line shows f/s with overall media and elapsed time,
                // second line shows recent photos per minute (media)
                var elapsed = _speedWatch?.Elapsed ?? TimeSpan.Zero;
                int hours = (int)elapsed.TotalHours;
                int minutes = elapsed.Minutes;
                int seconds = elapsed.Seconds;
                var elapsedStr = $"{hours}h {minutes}m {seconds}s";

                SpeedCounter = $"{avgRecent:0.00} f/s (media: {overall:0.00} f/s) - {elapsedStr}{Environment.NewLine}media: {recentPerMin:0.00} f/m";
            }
            catch
            {
                // Swallow unlikely errors from timing/queue operations but keep UI responsive
            }
        }

        private void OnImageProcessed(object? sender, Tuple<string, int> args)
        {
            // Increment atomic processed counter once and use its value for all UI updates
            var processed = System.Threading.Interlocked.Increment(ref _processedAtomic);
            ProcessedImagesCount = processed;
            TotalImagesCount = args.Item2;
            ProgressBarMaximum = args.Item2;
            ProgressBarValue = processed;
            ProcessingStatus = args.Item1;
        }

        private void FixPaths()
        {
            SourcePath = FixPath(SourcePath);
            DestinationPath = FixPath(DestinationPath);
        }

        private string FixPath(string path)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                return string.Empty;
            }

            // Trim leading/trailing quotes
            path = path.Trim().Trim('"');

            // Normalize directory separators
            path = path.Replace('/', System.IO.Path.DirectorySeparatorChar)
                .Replace('\\', System.IO.Path.DirectorySeparatorChar);

            // Remove trailing separators then add one back
            path = path.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar;

            return path;
        }

        private async Task CancelOperation()
        {
            try
            {
                var tokenSource = MainToken;
                if (tokenSource is not null)
                {
                    // Cancel synchronously and return to caller. Some CTSource implementations
                    // may provide async helpers but cancelling is immediate.
                    try
                    {
                        tokenSource.Cancel();
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Exception while cancelling token");
                    }
                }

                UiEnabled = true;
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error canceling the token");
                _logger.LogInformation("Ignora questo errore");
            }
        }

        // Note: These commands will trigger events that the View will handle to show dialogs
        // since dialogs require UI context
        public event EventHandler SelectSourceFolderRequested;
        public event EventHandler SelectDestinationFolderRequested;
        public event EventHandler SelectLogoFileRequested;
        public event EventHandler SelectModelsFolderRequested;
        public event EventHandler SelectCsvOutputRequested;
        public event EventHandler<string> SaveSettingsRequested;
        public event EventHandler<string> LoadSettingsRequested;
        public event EventHandler SelectColorRequested;
        // Request that the View shows a message to the user (message, caption, icon)
        public event EventHandler<Tuple<string, string, MessageBoxIcon>> ShowMessageRequested;
        public event EventHandler SelectTransparentColorRequested;

        private void SelectSourceFolder(object parameter)
        {
            SelectSourceFolderRequested?.Invoke(this, EventArgs.Empty);
        }

        private void SelectDestinationFolder(object parameter)
        {
            SelectDestinationFolderRequested?.Invoke(this, EventArgs.Empty);
        }

        private void SelectLogoFile(object parameter)
        {
            SelectLogoFileRequested?.Invoke(this, EventArgs.Empty);
        }

        private void SelectModelsFolder(object parameter)
        {
            SelectModelsFolderRequested?.Invoke(this, EventArgs.Empty);
        }

        private void SelectCsvOutput(object parameter)
        {
            SelectCsvOutputRequested?.Invoke(this, EventArgs.Empty);
        }

        private void SaveSettings(object parameter)
        {
            SaveSettingsRequested?.Invoke(this, null);
        }

        private void LoadSettings(object parameter)
        {
            LoadSettingsRequested?.Invoke(this, null);
        }

        private void SelectColor(object parameter)
        {
            SelectColorRequested?.Invoke(this, EventArgs.Empty);
        }

        private void SelectTransparentColor(object parameter)
        {
            SelectTransparentColorRequested?.Invoke(this, EventArgs.Empty);
        }

        public async Task SaveSettingsToFileAsync(string filePath)
        {
            await _settingsService.SaveSettingsAsync(filePath, this);
        }

        public async Task LoadSettingsFromFileAsync(string filePath)
        {
            await _settingsService.LoadSettingsAsync(filePath, this);
        }

        private string _appVersion = string.Empty;
        public string AppVersion
        {
            get => _appVersion;
            set
            {
                _appVersion = value;
                NotifyPropertyChanged();
            }
        }
    }
}


