using System;
using OpenCvSharp;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Вычисляет площадь каждого контура,
    /// находящегося в PipelineContext.
    ///
    /// Изображение и сами контуры не изменяются.
    /// </summary>
    internal sealed class ContourAreaExecutor : IPipelineBlockExecutor
    {
        public string BlockType => "ContourArea";

        public void Execute(PipelineContext context, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(context);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);

            ValidateContext(context, block);

            bool oriented = projectManager.GetBlockParameter(block.Id, "Oriented", false);

            ContourData contourData = context.Contours!;

            double[] areas = new double[contourData.Count];

            for (int contourIndex = 0; contourIndex < contourData.Count; contourIndex++)
            {
                OpenCvSharp. Point[] contour = contourData.Contours[contourIndex];

                /*
                 * Пустой или слишком короткий контур
                 * не может образовать площадь.
                 */
                if (contour == null || contour.Length < 3)
                {
                    areas[contourIndex] = 0;
                    continue;
                }

                areas[contourIndex] = Cv2.ContourArea(contour, oriented);
            }

            ContourAreaData areaData = new ContourAreaData(areas);

            context.ContourAreas = areaData;

            context.ResultText = CreateResultText(areaData);
        }

        /// <summary>
        /// Проверяет, что перед блоком
        /// были найдены контуры.
        /// </summary>
        private static void ValidateContext(PipelineContext context, ProjectBlock block)
        {
            if (context.Contours == null)
                throw new InvalidOperationException($"Перед блоком «{block.Name}» должен быть выполнен блок FindContours.");
        }

        /// <summary>
        /// Формирует краткое описание результата.
        /// </summary>
        private static string CreateResultText(ContourAreaData areaData)
        {
            if (areaData.IsEmpty)
                return "Контуры отсутствуют. Площади не рассчитаны.";

            return $"Рассчитано площадей: {areaData.Count}; минимальная: {areaData.MinimumArea:F2}; максимальная: {areaData.MaximumArea:F2}; общая: {areaData.TotalArea:F2}.";
        }
    }
}