using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using XplorePlane.Models;
using XplorePlane.Services;

namespace XplorePlane.ViewModels
{
    public class PipelineEditorViewModel : BindableBase
    {
        private const int MaxPipelineLength = 20;
        private const int DebounceDelayMs = 300;

        private readonly IImageProcessingService _imageProcessingService;
        private readonly IPipelineExecutionService _executionService;
        private readonly IPipelinePersistenceService _persistenceService;

        private PipelineNodeViewModel _selectedNode;
        private BitmapSource _sourceImage;
        private BitmapSource _previewImage;
        private string _pipelineName = "新建流水线";
        private string _selectedDevice = string.Empty;
        private bool _isExecuting;
        private string _statusMessage = string.Empty;
        private string _currentFilePath;

        private CancellationTokenSource _executionCts;
        private CancellationTokenSource _debounceCts;

        public PipelineEditorViewModel(
            IImageProcessingService imageProcessingService,
            IPipelineExecutionService executionService,
            IPipelinePersistenceService persistenceService)
        {
            _imageProcessingService = imageProcessingService ?? throw new ArgumentNullException(nameof(imageProcessingService));
            _executionService = executionService ?? throw new ArgumentNullException(nameof(executionService));
            _persistenceService = persistenceService ?? throw new ArgumentNullException(nameof(persistenceService));

            PipelineNodes = new ObservableCollection<PipelineNodeViewModel>();
            AvailableDevices = new ObservableCollection<string>();

            AddOperatorCommand = new DelegateCommand<string>(AddOperator, CanAddOperator);
            RemoveOperatorCommand = new DelegateCommand<PipelineNodeViewModel>(RemoveOperator);
            ReorderOperatorCommand = new DelegateCommand<PipelineReorderArgs>(ReorderOperator);
            ExecutePipelineCommand = new DelegateCommand(async () => await ExecutePipelineAsync(), () => !IsExecuting && SourceImage != null);
            CancelExecutionCommand = new DelegateCommand(CancelExecution, () => IsExecuting);
            NewPipelineCommand = new DelegateCommand(NewPipeline);
            SavePipelineCommand = new DelegateCommand(async () => await SavePipelineAsync());
            SaveAsPipelineCommand = new DelegateCommand(async () => await SaveAsPipelineAsync());
            DeletePipelineCommand = new DelegateCommand(async () => await DeletePipelineAsync());
            LoadPipelineCommand = new DelegateCommand(async () => await LoadPipelineAsync());
            OpenToolboxCommand = new DelegateCommand(OpenToolbox);
            MoveNodeUpCommand = new DelegateCommand<PipelineNodeViewModel>(MoveNodeUp);
            MoveNodeDownCommand = new DelegateCommand<PipelineNodeViewModel>(MoveNodeDown);
        }

   

        // ── State Properties ──────────────────────────────────────────

        public ObservableCollection<PipelineNodeViewModel> PipelineNodes { get; }
        public ObservableCollection<string> AvailableDevices { get; }

        public PipelineNodeViewModel SelectedNode
        {
            get => _selectedNode;
            set
            {
                if (SetProperty(ref _selectedNode, value) && value != null)
                    LoadNodeParameters(value);
            }
        }

        public BitmapSource SourceImage
        {
            get => _sourceImage;
            set
            {
                if (SetProperty(ref _sourceImage, value))
                {
                    ExecutePipelineCommand.RaiseCanExecuteChanged();
                    TriggerDebouncedExecution();
                }
            }
        }

        public BitmapSource PreviewImage
        {
            get => _previewImage;
            set => SetProperty(ref _previewImage, value);
        }

        public string PipelineName
        {
            get => _pipelineName;
            set => SetProperty(ref _pipelineName, value);
        }

        public string SelectedDevice
        {
            get => _selectedDevice;
            set => SetProperty(ref _selectedDevice, value);
        }

        public bool IsExecuting
        {
            get => _isExecuting;
            private set
            {
                if (SetProperty(ref _isExecuting, value))
                {
                    ExecutePipelineCommand.RaiseCanExecuteChanged();
                    CancelExecutionCommand.RaiseCanExecuteChanged();
                }
            }
        }

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

        // ── Commands ──────────────────────────────────────────────────

        public DelegateCommand<string> AddOperatorCommand { get; }
        public DelegateCommand<PipelineNodeViewModel> RemoveOperatorCommand { get; }
        public DelegateCommand<PipelineReorderArgs> ReorderOperatorCommand { get; }
        public DelegateCommand ExecutePipelineCommand { get; }
        public DelegateCommand CancelExecutionCommand { get; }
        public DelegateCommand NewPipelineCommand { get; }
        public DelegateCommand SavePipelineCommand { get; }
        public DelegateCommand SaveAsPipelineCommand { get; }
        public DelegateCommand DeletePipelineCommand { get; }
        public DelegateCommand LoadPipelineCommand { get; }

        public DelegateCommand OpenToolboxCommand { get; }

        public DelegateCommand<PipelineNodeViewModel> MoveNodeUpCommand { get; }
        public DelegateCommand<PipelineNodeViewModel> MoveNodeDownCommand { get; }

        // ── Command Implementations ───────────────────────────────────

        private bool CanAddOperator(string operatorKey) =>
            !string.IsNullOrWhiteSpace(operatorKey) && PipelineNodes.Count < MaxPipelineLength;

        private void AddOperator(string operatorKey)
        {
            Serilog.Log.Debug("AddOperator 被调用，operatorKey={OperatorKey}", operatorKey);

            if (string.IsNullOrWhiteSpace(operatorKey))
            {
                StatusMessage = "算子键不能为空";
                Serilog.Log.Warning("AddOperator 失败：operatorKey 为空");
                return;
            }

            var available = _imageProcessingService.GetAvailableProcessors();
            Serilog.Log.Debug("可用算子数量：{Count}，包含 {Key}：{Contains}",
                available.Count(), operatorKey, available.Contains(operatorKey));

            if (!available.Contains(operatorKey))
            {
                StatusMessage = $"算子 '{operatorKey}' 未注册";
                Serilog.Log.Warning("AddOperator 失败：算子 {Key} 未注册", operatorKey);
                return;
            }

            if (PipelineNodes.Count >= MaxPipelineLength)
            {
                StatusMessage = $"流水线节点数已达上限（{MaxPipelineLength}）";
                Serilog.Log.Warning("AddOperator 失败：节点数已达上限 {Max}", MaxPipelineLength);
                return;
            }

            var displayName = _imageProcessingService.GetProcessorDisplayName(operatorKey) ?? operatorKey;
            var node = new PipelineNodeViewModel(operatorKey, displayName)
            {
                Order = PipelineNodes.Count
            };
            LoadNodeParameters(node);
            PipelineNodes.Add(node);
            Serilog.Log.Information("节点已添加到 PipelineNodes：{Key} ({DisplayName})，当前节点数={Count}",
                operatorKey, displayName, PipelineNodes.Count);
            StatusMessage = $"已添加算子：{displayName}";
            TriggerDebouncedExecution();
        }

        private void RemoveOperator(PipelineNodeViewModel node)
        {
            if (node == null || !PipelineNodes.Contains(node)) return;

            PipelineNodes.Remove(node);
            RenumberNodes();

            if (SelectedNode == node)
                SelectedNode = null;

            StatusMessage = $"已移除算子：{node.DisplayName}";
            TriggerDebouncedExecution();
        }

        private void MoveNodeUp(PipelineNodeViewModel node)
        {
            if (node == null) return;
            int index = PipelineNodes.IndexOf(node);
            if (index <= 0) return;
            PipelineNodes.Move(index, index - 1);
            RenumberNodes();
            TriggerDebouncedExecution();
        }

        private void MoveNodeDown(PipelineNodeViewModel node)
        {
            if (node == null) return;
            int index = PipelineNodes.IndexOf(node);
            if (index < 0 || index >= PipelineNodes.Count - 1) return;
            PipelineNodes.Move(index, index + 1);
            RenumberNodes();
            TriggerDebouncedExecution();
        }

        private void ReorderOperator(PipelineReorderArgs args)
        {
            if (args == null) return;
            int oldIndex = args.OldIndex;
            int newIndex = args.NewIndex;

            if (oldIndex < 0 || oldIndex >= PipelineNodes.Count) return;
            if (newIndex < 0 || newIndex >= PipelineNodes.Count) return;
            if (oldIndex == newIndex) return;

            var node = PipelineNodes[oldIndex];
            PipelineNodes.RemoveAt(oldIndex);
            PipelineNodes.Insert(newIndex, node);
            RenumberNodes();
            TriggerDebouncedExecution();
        }

        private void RenumberNodes()
        {
            for (int i = 0; i < PipelineNodes.Count; i++)
                PipelineNodes[i].Order = i;
        }

        private void LoadNodeParameters(PipelineNodeViewModel node)
        {
            var paramDefs = _imageProcessingService.GetProcessorParameters(node.OperatorKey);
            if (paramDefs == null) return;

            // 保留已有参数快照
            var snapshot = node.Parameters.ToDictionary(p => p.Name, p => p.Value);
            node.Parameters.Clear();

            foreach (var paramDef in paramDefs)
            {
                var vm = new ProcessorParameterVM(paramDef);
                if (snapshot.TryGetValue(paramDef.Name, out var savedValue))
                    vm.Value = savedValue;
                vm.PropertyChanged += (_, e) =>
                {
                    if (e.PropertyName == nameof(ProcessorParameterVM.Value))
                        TriggerDebouncedExecution();
                };
                node.Parameters.Add(vm);
            }
        }

        private async Task ExecutePipelineAsync()
        {
            if (SourceImage == null || IsExecuting) return;

            _executionCts?.Cancel();
            _executionCts = new CancellationTokenSource();
            var token = _executionCts.Token;

            IsExecuting = true;
            StatusMessage = "正在执行流水线...";

            try
            {
                var progress = new Progress<PipelineProgress>(p =>
                    StatusMessage = $"执行中：{p.CurrentOperator} ({p.CurrentStep}/{p.TotalSteps})");

                var result = await _executionService.ExecutePipelineAsync(
                    PipelineNodes, SourceImage, progress, token);

                PreviewImage = result;
                StatusMessage = "流水线执行完成";
            }
            catch (OperationCanceledException)
            {
                StatusMessage = "流水线执行已取消";
            }
            catch (PipelineExecutionException ex)
            {
                StatusMessage = $"节点 '{ex.FailedOperatorKey}' 执行失败：{ex.Message}";
            }
            catch (Exception ex)
            {
                StatusMessage = $"执行错误：{ex.Message}";
            }
            finally
            {
                IsExecuting = false;
            }
        }

        private void CancelExecution()
        {
            _executionCts?.Cancel();
        }

        private void TriggerDebouncedExecution()
        {
            if (SourceImage == null) return;

            _debounceCts?.Cancel();
            _debounceCts = new CancellationTokenSource();
            var token = _debounceCts.Token;

            Task.Delay(DebounceDelayMs, token).ContinueWith(t =>
            {
                if (!t.IsCanceled)
                    _ = ExecutePipelineAsync();
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void NewPipeline()
        {
            PipelineNodes.Clear();
            SelectedNode = null;
            PipelineName = "新建流水线";
            PreviewImage = null;
            _currentFilePath = null;
            StatusMessage = "已新建流水线";
        }

        private async Task SavePipelineAsync()
        {
            if (string.IsNullOrWhiteSpace(PipelineName) || PipelineName.Length > 100)
            {
                StatusMessage = "流水线名称不能为空且长度不超过 100 个字符";
                return;
            }

            if (string.IsNullOrEmpty(_currentFilePath))
            {
                await SaveAsPipelineAsync();
                return;
            }

            await SaveToFileAsync(_currentFilePath);
        }

        private async Task SaveAsPipelineAsync()
        {
            if (string.IsNullOrWhiteSpace(PipelineName) || PipelineName.Length > 100)
            {
                StatusMessage = "流水线名称不能为空且长度不超过 100 个字符";
                return;
            }

            var dialog = new SaveFileDialog
            {
                Filter = "流水线文件 (*.pipeline.json)|*.pipeline.json",
                FileName = PipelineName,
                InitialDirectory = GetPipelineDirectory()
            };

            if (dialog.ShowDialog() == true)
            {
                _currentFilePath = dialog.FileName;
                await SaveToFileAsync(_currentFilePath);
            }
        }

        private async Task SaveToFileAsync(string filePath)
        {
            try
            {
                var model = BuildPipelineModel();
                await _persistenceService.SaveAsync(model, filePath);
                StatusMessage = $"流水线已保存：{Path.GetFileName(filePath)}";
            }
            catch (IOException ex)
            {
                StatusMessage = $"保存失败：{ex.Message}";
            }
        }

        private async Task DeletePipelineAsync()
        {
            if (string.IsNullOrEmpty(_currentFilePath)) return;

            try
            {
                if (File.Exists(_currentFilePath))
                    File.Delete(_currentFilePath);

                NewPipeline();
                StatusMessage = "流水线已删除";
            }
            catch (IOException ex)
            {
                StatusMessage = $"删除失败：{ex.Message}";
            }
            await Task.CompletedTask;
        }

        private async Task LoadPipelineAsync()
        {
            var dialog = new OpenFileDialog
            {
                Filter = "流水线文件 (*.pipeline.json)|*.pipeline.json",
                InitialDirectory = GetPipelineDirectory()
            };

            if (dialog.ShowDialog() != true) return;

            try
            {
                var model = await _persistenceService.LoadAsync(dialog.FileName);

                PipelineNodes.Clear();
                SelectedNode = null;

                PipelineName = model.Name;
                SelectedDevice = model.DeviceId;
                _currentFilePath = dialog.FileName;

                foreach (var nodeModel in model.Nodes)
                {
                    var displayName = _imageProcessingService.GetProcessorDisplayName(nodeModel.OperatorKey)
                                      ?? nodeModel.OperatorKey;
                    var node = new PipelineNodeViewModel(nodeModel.OperatorKey, displayName)
                    {
                        Order = nodeModel.Order,
                        IsEnabled = nodeModel.IsEnabled
                    };
                    LoadNodeParameters(node);

                    // 恢复已保存的参数值
                    foreach (var param in node.Parameters)
                    {
                        if (nodeModel.Parameters.TryGetValue(param.Name, out var savedValue))
                            param.Value = savedValue;
                    }

                    PipelineNodes.Add(node);
                }

                Serilog.Log.Information("流水线已加载：{Name}，节点数={Count}", model.Name, PipelineNodes.Count);
                StatusMessage = $"已加载流水线：{model.Name}（{PipelineNodes.Count} 个节点）";
            }
            catch (Exception ex)
            {
                Serilog.Log.Warning("加载流水线失败：{Error}", ex.Message);
                StatusMessage = $"加载失败：{ex.Message}";
            }
        }

        private void OpenToolbox() //打开图像工具箱
        {
            Serilog.Log.Information("OpenToolbox 被调用");
            try
            {
                var window = new Views.OperatorToolboxWindow
                {
                    Owner = System.Windows.Application.Current.MainWindow
                };
                Serilog.Log.Information("OperatorToolboxWindow 已创建，准备 Show()");
                window.Show();
                Serilog.Log.Information("OperatorToolboxWindow.Show() 完成");
            }
            catch (Exception ex)
            {
                Serilog.Log.Error(ex, "OpenToolbox 打开窗口失败");
            }
        }


        private PipelineModel BuildPipelineModel()
        {
            return new PipelineModel
            {
                Name = PipelineName,
                DeviceId = SelectedDevice,
                UpdatedAt = DateTime.UtcNow,
                Nodes = PipelineNodes.Select(n => new PipelineNodeModel
                {
                    Id = n.Id,
                    OperatorKey = n.OperatorKey,
                    Order = n.Order,
                    IsEnabled = n.IsEnabled,
                    Parameters = n.Parameters.ToDictionary(p => p.Name, p => p.Value)
                }).ToList()
            };
        }

        private static string GetPipelineDirectory()
        {
            var dir = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                "XplorePlane", "Pipelines");
            Directory.CreateDirectory(dir);
            return dir;
        }
    }
}
