using System;
using OpenCvSharp;
namespace OpenCVStudio_v0
{
    public sealed class AddBorderExecutor : IImageBlockExecutor
    {
        public string BlockType => "AddBorder";
        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(input);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (input.Empty()) throw new ArgumentException("В блок добавления полей передано пустое изображение.", nameof(input));
            int top = projectManager.GetBlockParameter(block.Id, "Top", 50);
            int bottom = projectManager.GetBlockParameter(block.Id, "Bottom", 50);
            int left = projectManager.GetBlockParameter(block.Id, "Left", 50);
            int right = projectManager.GetBlockParameter(block.Id, "Right", 50);
            RotateBorderMode borderMode = projectManager.GetBlockParameter(block.Id, "BorderMode", RotateBorderMode.Constant);
            double borderValue = projectManager.GetBlockParameter(block.Id, "BorderValue", 0.0);
            ValidateParameters(input, top, bottom, left, right, borderMode, borderValue);
            Mat output = new Mat();
            try
            {
                Cv2.CopyMakeBorder(input, output, top, bottom, left, right, ConvertBorderMode(borderMode), Scalar.All(borderValue));
                if (output.Empty()) throw new InvalidOperationException("Блок добавления полей вернул пустое изображение.");
                return output;
            }
            catch { output.Dispose(); throw; }
        }
        private static BorderTypes ConvertBorderMode(RotateBorderMode borderMode)
        {
            return borderMode switch
            {
                RotateBorderMode.Constant => BorderTypes.Constant,
                RotateBorderMode.Replicate => BorderTypes.Replicate,
                RotateBorderMode.Reflect => BorderTypes.Reflect,
                RotateBorderMode.Reflect101 => BorderTypes.Reflect101,
                _ => throw new ArgumentOutOfRangeException(nameof(borderMode), borderMode, "Неизвестный режим заполнения полей.")
            };
        }
        private static void ValidateParameters(Mat input, int top, int bottom, int left, int right, RotateBorderMode borderMode, double borderValue)
        {
            ValidateBorderSize(top, nameof(top));
            ValidateBorderSize(bottom, nameof(bottom));
            ValidateBorderSize(left, nameof(left));
            ValidateBorderSize(right, nameof(right));
            if (!Enum.IsDefined(borderMode)) throw new ArgumentOutOfRangeException(nameof(borderMode), borderMode, "Неизвестный режим заполнения полей.");
            if (double.IsNaN(borderValue) || double.IsInfinity(borderValue) || borderValue < 0.0 || borderValue > 255.0)
                throw new ArgumentException("Значение фона должно быть от 0 до 255.");
            long resultWidth = (long)input.Width + left + right;
            long resultHeight = (long)input.Height + top + bottom;
            if (resultWidth > int.MaxValue || resultHeight > int.MaxValue)
                throw new ArgumentException("Размер результата после добавления полей слишком велик.");
        }
        private static void ValidateBorderSize(int value, string parameterName)
        {
            if (value < 0 || value > 100000)
                throw new ArgumentOutOfRangeException(parameterName, value, "Размер поля должен быть от 0 до 100000 пикселей.");
        }
    }
}