using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using Serilog;
using XplorePlane.Services;

namespace XplorePlane.ViewModels
{
    /// <summary>算子列表项：持有注册 key 和本地化显示名</summary>
    public class ProcessorItem
    {
        public string Key { get; }
        public string DisplayName { get; }
        public ProcessorItem(string key, string displayName) { Key = key; DisplayName = displayName; }
        public override string ToString() => DisplayName;
    }
    public class ImageProcessingViewModel : BindableBase
    {
        private readonly IImageProcessingService _imageProcessingService;
        private readonly ILogger _logger;

        private ProcessorItem _selectedProcessorItem;
        private BitmapSource _currentImage;
        private BitmapSource _originalImage;
        private double _processingProgress;
        private bool _isProcessing;
        private string _statusMessage;

        public ImageProcessingViewModel(IImageProcessingService imageProcessingService, ILogger logger)
        {
            _imageProcessingService = imageProcessingService;
            _logger = logger;

            AvailableProcessors = new ObservableCollection<ProcessorItem>();
            CurrentParameters = new ObservableCollection<ProcessorParameterVM>();

            foreach (var key in _imageProcessingService.GetAvailableProcessors())
                AvailableProcessors.Add(new ProcessorItem(key, _imageProcessingService.GetProcessorDisplayName(key)));

            SelectProcessorCommand = new DelegateCommand<string>(OnSelectProcessor);
            ApplyProcessingCommand = new DelegateCommand(OnApplyProcessing);
            ResetImageCommand = new DelegateCommand(OnResetImage);
            LoadImageCommand = new DelegateCommand(OnLoadImage);
            SaveResultCommand = new DelegateCommand(OnSaveResult, () => CurrentImage != null);
        }

        public ObservableCollection<ProcessorItem> AvailableProcessors { get; }
        public ObservableCollection<ProcessorParameterVM> CurrentParameters { get; }

        public ProcessorItem SelectedProcessorItem
        {
            get => _selectedProcessorItem;
            set
            {
                SetProperty(ref _selectedProcessorItem, value);
                if (value != null) OnSelectProcessor(value.Key);
            }
        }

        // Keep SelectedProcessor as the key string for service calls
        public string SelectedProcessor => _selectedProcessorItem?.Key;

        public BitmapSource CurrentImage
        {
            get => _currentImage;
            set
            {
                SetProperty(ref _currentImage, value);
                SaveResultCommand?.RaiseCanExecuteChanged();
            }
        }

        public BitmapSource OriginalImage
        {
            get => _originalImage;
            set => SetProperty(ref _originalImage, value);
        }

        public double ProcessingProgress
        {
            get => _processingProgress;
            set => SetProperty(ref _processingProgress, value);
        }

        public bool IsProcessing
        {
            get => _isProcessing;
            set => SetProperty(ref _isProcessing, value);
        }

        public string StatusMessage
        {
            get => _statusMessage;
            set => SetProperty(ref _statusMessage, value);
        }

        public DelegateCommand<string> SelectProcessorCommand { get; }
        public DelegateCommand ApplyProcessingCommand { get; }
        public DelegateCommand ResetImageCommand { get; }
        public DelegateCommand LoadImageCommand { get; }
        public DelegateCommand SaveResultCommand { get; }

        private void OnSelectProcessor(string processorName)
        {
            if (string.IsNullOrEmpty(processorName)) return;

            try
            {
                var parameters = _imageProcessingService.GetProcessorParameters(processorName);
                CurrentParameters.Clear();
                foreach (var param in parameters)
                    CurrentParameters.Add(new ProcessorParameterVM(param));
            }
            catch (ArgumentException ex)
            {
                StatusMessage = $"Error loading parameters: {ex.Message}";
                _logger.Warning(ex, "Failed to load parameters for processor: {ProcessorName}", processorName);
            }
        }
        private async void OnApplyProcessing()
        {
            if (CurrentImage == null || string.IsNullOrEmpty(SelectedProcessor)) return;

            IsProcessing = true;
            ProcessingProgress = 0;

            try
            {
                var parameters = new Dictionary<string, object>();
                foreach (var param in CurrentParameters)
                    parameters[param.Name] = param.Value;

                var progress = new Progress<double>(p => ProcessingProgress = p);

                var result = await _imageProcessingService.ProcessImageAsync(
                    CurrentImage,
                    SelectedProcessor,
                    parameters,
                    progress);

                CurrentImage = result;
                StatusMessage = $"Processing complete: {SelectedProcessor}";
                _logger.Information("Image processing completed: {ProcessorName}", SelectedProcessor);
            }
            catch (ArgumentException ex)
            {
                StatusMessage = $"Processing error: {ex.Message}";
                _logger.Warning(ex, "Processing failed for processor: {ProcessorName}", SelectedProcessor);
                // CurrentImage unchanged
            }
            catch (OperationCanceledException)
            {
                StatusMessage = "Processing cancelled";
                _logger.Information("Image processing cancelled");
                // CurrentImage unchanged
            }
            catch (ImageProcessingException ex)
            {
                StatusMessage = $"Processing failed: {ex.Message}";
                _logger.Error(ex, "Image processing exception for processor: {ProcessorName}", SelectedProcessor);
                // CurrentImage unchanged
            }
            finally
            {
                IsProcessing = false;
            }
        }
        private void OnResetImage()
        {
            CurrentImage = OriginalImage;
            StatusMessage = "Image reset to original";
            ProcessingProgress = 0;
        }

        private void OnLoadImage()
        {
            var dlg = new OpenFileDialog
            {
                Title = "加载图像",
                Filter = "图像文件|*.bmp;*.png;*.jpg;*.jpeg;*.tif;*.tiff|所有文件|*.*"
            };
            if (dlg.ShowDialog() != true) return;

            try
            {
                var bitmap = new BitmapImage();
                bitmap.BeginInit();
                bitmap.UriSource = new Uri(dlg.FileName);
                bitmap.CacheOption = BitmapCacheOption.OnLoad;
                bitmap.EndInit();
                bitmap.Freeze();

                OriginalImage = bitmap;
                CurrentImage = bitmap;
                StatusMessage = $"已加载：{Path.GetFileName(dlg.FileName)}";
                ProcessingProgress = 0;
            }
            catch (Exception ex)
            {
                StatusMessage = $"加载失败：{ex.Message}";
                _logger.Error(ex, "Failed to load image: {Path}", dlg.FileName);
            }
        }

        private void OnSaveResult()
        {
            if (CurrentImage == null) return;

            var dlg = new SaveFileDialog
            {
                Title = "保存结果",
                Filter = "PNG 图像|*.png|BMP 图像|*.bmp|JPEG 图像|*.jpg",
                DefaultExt = ".png"
            };
            if (dlg.ShowDialog() != true) return;

            try
            {
                BitmapEncoder encoder = Path.GetExtension(dlg.FileName).ToLower() switch
                {
                    ".bmp" => new BmpBitmapEncoder(),
                    ".jpg" or ".jpeg" => new JpegBitmapEncoder(),
                    _ => new PngBitmapEncoder()
                };
                encoder.Frames.Add(BitmapFrame.Create(CurrentImage));
                using var stream = File.OpenWrite(dlg.FileName);
                encoder.Save(stream);
                StatusMessage = $"已保存：{Path.GetFileName(dlg.FileName)}";
            }
            catch (Exception ex)
            {
                StatusMessage = $"保存失败：{ex.Message}";
                _logger.Error(ex, "Failed to save image: {Path}", dlg.FileName);
            }
        }
    }
}
