using OpenCvSharp;
namespace OpenCVStudio_v0
{
    /// <summary>
    /// Преобразует изображение в выбранное цветовое пространство
    /// и извлекает один канал.
    /// </summary>
    public sealed class ColorChannelExecutor : IImageBlockExecutor
    {
        public string BlockType => "ColorChannel";
        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(input);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (input.Empty()) throw new ArgumentException("В блок ColorChannel передано пустое изображение.", nameof(input));
            ColorSpaceMode colorSpace = projectManager.GetBlockParameter(block.Id, "ColorSpace", ColorSpaceMode.BGR);
            int channel = projectManager.GetBlockParameter(block.Id, "Channel", 0);
            ValidateChannel(channel);
            using Mat convertedImage = ConvertColorSpace(input, colorSpace);
            Mat output = new Mat();
            Cv2.ExtractChannel(convertedImage, output, channel);
            if (output.Empty()) { output.Dispose(); throw new InvalidOperationException($"Не удалось извлечь канал {channel} из цветового пространства {colorSpace}."); }
            return output;
        }
        private static Mat ConvertColorSpace(Mat input, ColorSpaceMode colorSpace)
        {
            if (colorSpace == ColorSpaceMode.BGR) return input.Clone();
            Mat converted = new Mat();
            ColorConversionCodes conversionCode = colorSpace switch
            {
                ColorSpaceMode.HSV => ColorConversionCodes.BGR2HSV,
                ColorSpaceMode.HLS => ColorConversionCodes.BGR2HLS,
                ColorSpaceMode.Lab => ColorConversionCodes.BGR2Lab,
                ColorSpaceMode.YCrCb => ColorConversionCodes.BGR2YCrCb,
                _ => throw new ArgumentOutOfRangeException(nameof(colorSpace), colorSpace, "Неизвестное цветовое пространство.")
            };
            Cv2.CvtColor(input, converted, conversionCode);
            return converted;
        }
        private static void ValidateChannel(int channel)
        {
            if (channel is < 0 or > 2) throw new ArgumentOutOfRangeException(nameof(channel), channel, "Номер канала должен находиться в диапазоне от 0 до 2.");
        }
    }
}