using System;
using OpenCvSharp;

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

        public void Execute(PipelineContext context, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(context);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            ValidateContext(context, block);
            bool closed = projectManager.GetBlockParameter(block.Id, "Closed", true);
            ContourData contourData = context.Contours!;
            double[] lengths = new double[contourData.Count];
            for (int contourIndex = 0; contourIndex < contourData.Count; contourIndex++)
            {
               OpenCvSharp. Point[] contour = contourData.Contours[contourIndex];
                /*
                 * Для вычисления длины линии
                 * необходимо минимум две точки.
                 */
                if (contour == null || contour.Length < 2)
                {
                    lengths[contourIndex] = 0;
                    continue;
                }
                lengths[contourIndex] = Cv2.ArcLength(contour, closed);
            }
            ArcLengthData arcLengthData = new ArcLengthData(lengths);
            context.ArcLengths = arcLengthData;
            context.ResultText = CreateResultText(arcLengthData);
        }

        /// <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(ArcLengthData arcLengthData)
        {
            if (arcLengthData.IsEmpty)
            {
                return "Контуры отсутствуют. Длины не рассчитаны.";
            }
            return $"Рассчитано длин: {arcLengthData.Count}; минимальная: {arcLengthData.MinimumLength:F2}; максимальная: {arcLengthData.MaximumLength:F2}; общая: {arcLengthData.TotalLength:F2}.";
        }
    }
}