using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using XplorePlane.ViewModels;

namespace XplorePlane.Services
{
    public class PipelineExecutionService : IPipelineExecutionService
    {
        private const int PreviewMaxHeight = 1080;
        private const int UhdThreshold = 3840;

        private readonly IImageProcessingService _imageProcessingService;

        public PipelineExecutionService(IImageProcessingService imageProcessingService)
        {
            _imageProcessingService = imageProcessingService ?? throw new ArgumentNullException(nameof(imageProcessingService));
        }

        public async Task<BitmapSource> ExecutePipelineAsync(
            IEnumerable<PipelineNodeViewModel> nodes,
            BitmapSource source,
            IProgress<PipelineProgress> progress = null,
            CancellationToken cancellationToken = default)
        {
            if (source == null) throw new ArgumentNullException(nameof(source));

            var enabledNodes = (nodes ?? Enumerable.Empty<PipelineNodeViewModel>())
                .Where(n => n.IsEnabled)
                .OrderBy(n => n.Order)
                .ToList();

            if (enabledNodes.Count == 0)
                return source;

            // 大图像预览缩放
            var current = ScaleForPreview(source);

            int total = enabledNodes.Count;
            for (int step = 0; step < total; step++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var node = enabledNodes[step];
                var parameters = node.Parameters
                    .Where(p => p.IsValueValid)
                    .ToDictionary(p => p.Name, p => p.Value);

                try
                {
                    current = await _imageProcessingService.ProcessImageAsync(
                        current, node.OperatorKey, parameters, null, cancellationToken);

                    if (current == null)
                        throw new PipelineExecutionException(
                            $"算子 '{node.OperatorKey}' 返回了空图像",
                            node.Order, node.OperatorKey);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (PipelineExecutionException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    throw new PipelineExecutionException(
                        $"算子 '{node.DisplayName}' 执行失败：{ex.Message}",
                        node.Order, node.OperatorKey, ex);
                }

                progress?.Report(new PipelineProgress(step + 1, total, node.DisplayName));
            }

            if (!current.IsFrozen)
                current.Freeze();

            return current;
        }

        private static BitmapSource ScaleForPreview(BitmapSource source)
        {
            if (source.PixelWidth <= UhdThreshold && source.PixelHeight <= UhdThreshold)
                return source;

            double scale = (double)PreviewMaxHeight / source.PixelHeight;
            if (source.PixelWidth * scale > UhdThreshold)
                scale = (double)UhdThreshold / source.PixelWidth;

            var scaled = new TransformedBitmap(source, new ScaleTransform(scale, scale));
            scaled.Freeze();
            return scaled;
        }
    }
}
