using System;
using System.Collections.Generic;
using OpenCvSharp;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Собирает цветное изображение
    /// из коллекции каналов.
    ///
    /// Вход:
    /// context.Channels
    ///
    /// Выход:
    /// context.Image
    ///
    /// Порядок:
    /// 0 - Blue
    /// 1 - Green
    /// 2 - Red
    /// </summary>
    internal sealed class MergeChannelsExecutor : IChannelCollectionBlockExecutor
    {
        public string BlockType => "MergeChannels";

        public void Execute(PipelineContext context, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(context);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (!context.HasChannels)
            {
                throw new InvalidOperationException($"Блок «{block.Name}» не получил коллекцию каналов.");
            }
            IReadOnlyList<Mat> channels = context.Channels;
            if (channels.Count != 3)
            {
                throw new InvalidOperationException($"Блок «{block.Name}» требует 3 канала.\n\nПолучено: {channels.Count}");
            }
            ValidateChannels(channels, block);
            Mat result = new Mat();
            try
            {
                Cv2.Merge(channels.ToArray(), result);
                if (result.Empty())
                {
                    throw new InvalidOperationException($"Блок «{block.Name}» создал пустое изображение.");
                }
                context.ReplaceImage(result);
                result = null;
                context.ResultText = "Каналы объединены в цветное изображение BGR.";
            }
            finally
            {
                result?.Dispose();
            }
        }

        private static void ValidateChannels(IReadOnlyList<Mat> channels, ProjectBlock block)
        {
            OpenCvSharp. Size size = channels[0].Size();
            foreach (Mat channel in channels)
            {
                if (channel.Empty())
                {
                    throw new InvalidOperationException($"Блок «{block.Name}» получил пустой канал.");
                }
                if (channel.Channels() != 1)
                {
                    throw new InvalidOperationException($"Блок «{block.Name}» принимает только одноканальные изображения.");
                }
                if (channel.Size() != size)
                {
                    throw new InvalidOperationException($"Размеры каналов не совпадают.");
                }
            }
        }
    }
}