using System;
using OpenCvSharp;

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

        public void Execute(PipelineContext context, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(context);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            ValidateContext(context, block);
            ContourData contourData = context.Contours!;
            RotatedRect[] rectangles = new RotatedRect[contourData.Count];
            for (int contourIndex = 0; contourIndex < contourData.Count; contourIndex++)
            {
                OpenCvSharp.Point[] contour = contourData.Contours[contourIndex];
                rectangles[contourIndex] = CalculateRectangle(contour);
            }
            MinAreaRectData result = new MinAreaRectData(rectangles);
            context.MinAreaRects = result;
            context.ResultText = CreateResultText(result);
        }

        /// <summary>
        /// Вычисляет прямоугольник одного контура.
        /// </summary>
        private static RotatedRect CalculateRectangle(OpenCvSharp. Point[]? contour)
        {
            /*
             * MinAreaRect может работать даже
             * с одной точкой, но пустой массив
             * передавать нельзя.
             */
            if (contour == null || contour.Length == 0)
            {
                return new RotatedRect(new Point2f(0, 0), new Size2f(0, 0), 0);
            }
            return Cv2.MinAreaRect(contour);
        }

        /// <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(MinAreaRectData data)
        {
            if (data.IsEmpty)
            {
                return "Контуры отсутствуют. Повёрнутые прямоугольники не рассчитаны.";
            }
            RotatedRect largestRectangle = data.Rectangles[0];
            double largestArea = largestRectangle.Size.Width * largestRectangle.Size.Height;
            int largestIndex = 0;
            for (int index = 1; index < data.Rectangles.Length; index++)
            {
                RotatedRect rectangle = data.Rectangles[index];
                double area = rectangle.Size.Width * rectangle.Size.Height;
                if (area <= largestArea) continue;
                largestArea = area;
                largestRectangle = rectangle;
                largestIndex = index;
            }
            return $"Рассчитано прямоугольников: {data.Count}; крупнейший: контур {largestIndex}; центр X={largestRectangle.Center.X:F2}, Y={largestRectangle.Center.Y:F2}; размер {largestRectangle.Size.Width:F2} × {largestRectangle.Size.Height:F2}; угол {largestRectangle.Angle:F2}°.";
        }
    }
}