using System;
using System.Collections.Generic;
using System.Text;

using OpenCvSharp;
namespace OpenCVStudio_v0
{
    public sealed class BlurExecutor : IImageBlockExecutor
    {
        public string BlockType => "Blur";
        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(input);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (input.Empty()) throw new ArgumentException("В блок Blur передано пустое изображение.", nameof(input));
            BlurTypeMode blurType = projectManager.GetBlockParameter(block.Id, "BlurType", BlurTypeMode.Gaussian);
            int kernelWidth = projectManager.GetBlockParameter(block.Id, "KernelWidth", 5);
            int kernelHeight = projectManager.GetBlockParameter(block.Id, "KernelHeight", 5);
            double sigmaX = projectManager.GetBlockParameter(block.Id, "SigmaX", 0.0);
            ValidateParameters(blurType, kernelWidth, kernelHeight, sigmaX);
            Mat output = new Mat();
            try
            {
                switch (blurType)
                {
                    case BlurTypeMode.Average:
                        Cv2.Blur(input, output, new OpenCvSharp. Size(kernelWidth, kernelHeight));
                        break;
                    case BlurTypeMode.Gaussian:
                        Cv2.GaussianBlur(input, output, new OpenCvSharp.Size(kernelWidth, kernelHeight), sigmaX);
                        break;
                    case BlurTypeMode.Median:
                        Cv2.MedianBlur(input, output, kernelWidth);
                        break;
                    case BlurTypeMode.Bilateral:
                        Cv2.BilateralFilter(input, output, kernelWidth, sigmaX, sigmaX);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(blurType), blurType, "Неизвестный тип размытия.");
                }
                if (output.Empty()) throw new InvalidOperationException("Блок Blur вернул пустое изображение.");
                return output;
            }
            catch { output.Dispose(); throw; }
        }
        private static void ValidateParameters(BlurTypeMode blurType, int kernelWidth, int kernelHeight, double sigmaX)
        {
            if (kernelWidth < 1) throw new ArgumentOutOfRangeException(nameof(kernelWidth), "Ширина ядра должна быть больше нуля.");
            if (kernelHeight < 1) throw new ArgumentOutOfRangeException(nameof(kernelHeight), "Высота ядра должна быть больше нуля.");
            if (blurType is BlurTypeMode.Gaussian or BlurTypeMode.Median)
            {
                if (kernelWidth % 2 == 0) throw new ArgumentException("Ширина ядра должна быть нечётной.");
            }
            if (blurType == BlurTypeMode.Gaussian && kernelHeight % 2 == 0) throw new ArgumentException("Высота ядра должна быть нечётной.");
            if (blurType == BlurTypeMode.Median && kernelWidth != kernelHeight) throw new ArgumentException("Для Median ширина и высота ядра должны совпадать.");
            if (sigmaX < 0) throw new ArgumentOutOfRangeException(nameof(sigmaX), "Sigma X не может быть отрицательной.");
        }
    }
}