using System;
using OpenCvSharp;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Вычисляет абсолютную разницу
    /// между двумя изображениями.
    ///
    /// Первый вход:
    /// context.Image
    ///
    /// Второй вход:
    /// context.SecondImage
    ///
    /// Если второе изображение отсутствует,
    /// используется context.Image.
    ///
    /// Результат записывается обратно
    /// в context.Image.
    /// </summary>
    internal sealed class AbsDiffExecutor : TwoImagePipelineBlockExecutorBase
    {
        public override string BlockType => "AbsDiff";

        public override void Execute(PipelineContext context, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(context);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            ValidateFirstImage(context, block);
            bool usedSecondImage = context.HasSecondImage;
            Mat secondImage = GetSecondImage(context);
            ValidateSameFormat(context.Image, secondImage, block);
            Mat? resultImage = null;
            try
            {
                resultImage = new Mat();
                Cv2.Absdiff(context.Image, secondImage, resultImage);
                if (resultImage.Empty())
                {
                    throw new InvalidOperationException($"Блок «{block.Name}» вернул пустое изображение.");
                }
                /*
                 * Передаём результат обратно
                 * в основной поток pipeline.
                 */
                context.ReplaceImage(resultImage);
                resultImage = null;
                /*
                 * После математической операции
                 * старые геометрические данные
                 * больше не соответствуют изображению.
                 */
                ClearContourData(context);
                context.ResultText = usedSecondImage ? "Вычислена абсолютная разница двух изображений." : "Второе изображение отсутствует. Использовано основное изображение.";
            }
            finally
            {
                /*
                 * Если результат не был передан
                 * PipelineContext, освобождаем его.
                 */
                resultImage?.Dispose();
            }
        }

        private static void ClearContourData(PipelineContext context)
        {
            context.Contours = null;
            context.ContourAreas = null;
            context.ArcLengths = null;
            context.BoundingRects = null;
            context.MinAreaRects = null;
        }
    }
}