using System;
using OpenCvSharp;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Выбирает цветовые каналы из двух изображений.
    ///
    /// Вход:
    /// context.Image
    /// context.SecondImage
    ///
    /// Выход:
    /// context.Image
    /// context.SecondImage
    ///
    /// Если второе изображение отсутствует,
    /// используется первое.
    /// </summary>
    internal sealed class ChannelSelectorExecutor : ITwoOutputPipelineBlockExecutor
    {
        public string BlockType => "ChannelSelector";

        public void Execute(PipelineContext context, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(context);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (!context.HasImage)
            {
                throw new InvalidOperationException($"Блок «{block.Name}» не получил основное изображение.");
            }
            Mat firstImage = context.Image;
            Mat secondImage = context.HasSecondImage ? context.SecondImage : context.Image;
            ChannelSelectionMode firstChannel = projectManager.GetBlockParameter(block.Id, "FirstChannel", ChannelSelectionMode.Original);
            ChannelSelectionMode secondChannel = projectManager.GetBlockParameter(block.Id, "SecondChannel", ChannelSelectionMode.Original);
            Mat outputFirst = SelectChannel(firstImage, firstChannel);
            Mat outputSecond = SelectChannel(secondImage, secondChannel);
            try
            {
                context.ReplaceImage(outputFirst);
                context.ReplaceSecondImage(outputSecond);
                context.ResultText = "Выбраны каналы изображений.";
            }
            catch
            {
                outputFirst.Dispose();
                outputSecond.Dispose();
                throw;
            }
        }

        private static Mat SelectChannel(Mat source, ChannelSelectionMode mode)
        {
            if (mode == ChannelSelectionMode.Original)
            {
                return source.Clone();
            }
            if (source.Channels() != 3)
            {
                throw new InvalidOperationException("Выбор цветового канала возможен только для трехканального изображения BGR.");
            }
            Mat[] channels = Cv2.Split(source);
            try
            {
                Mat result = channels[(int)mode].Clone();
                return result;
            }
            finally
            {
                foreach (Mat channel in channels)
                {
                    channel.Dispose();
                }
            }
        }
    }
}