using System;
using System.Collections.Generic;
using System.Text;

using System;
using OpenCvSharp;
namespace OpenCVStudio_v0
{
    public sealed class ResizeExecutor : IImageBlockExecutor
    {
        public string BlockType => "Resize";
        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));
            ResizeMode mode = projectManager.GetBlockParameter(block.Id, "Mode", ResizeMode.ScalePercent);
            int width = projectManager.GetBlockParameter(block.Id, "Width", 640);
            int height = projectManager.GetBlockParameter(block.Id, "Height", 480);
            double scalePercent = projectManager.GetBlockParameter(block.Id, "ScalePercent", 100.0);
            bool keepAspectRatio = projectManager.GetBlockParameter(block.Id, "KeepAspectRatio", true);
            ResizeInterpolation interpolation = projectManager.GetBlockParameter(block.Id, "Interpolation", ResizeInterpolation.Area);
            ValidateParameters(mode, width, height, scalePercent);
             OpenCvSharp.Size targetSize = CalculateTargetSize(input, mode, width, height, scalePercent, keepAspectRatio);
            InterpolationFlags interpolationFlag = ConvertInterpolation(interpolation);
            Mat output = new Mat();
            try
            {
                Cv2.Resize(input, output, targetSize, 0, 0, interpolationFlag);
                if (output.Empty()) throw new InvalidOperationException("Resize вернул пустое изображение.");
                return output;
            }
            catch { output.Dispose(); throw; }
        }
        private static OpenCvSharp. Size CalculateTargetSize(Mat input, ResizeMode mode, int width, int height, double scalePercent, bool keepAspectRatio)
        {
            int targetWidth; int targetHeight;
            switch (mode)
            {
                case ResizeMode.ExactSize:
                    targetWidth = width;
                    if (keepAspectRatio)
                    {
                        double aspectRatio = (double)input.Height / input.Width;
                        targetHeight = (int)Math.Round(targetWidth * aspectRatio);
                    }
                    else targetHeight = height;
                    break;
                case ResizeMode.ScalePercent:
                    double scale = scalePercent / 100.0;
                    targetWidth = (int)Math.Round(input.Width * scale);
                    targetHeight = (int)Math.Round(input.Height * scale);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(mode), mode, "Неизвестный режим изменения размера.");
            }
            targetWidth = Math.Max(targetWidth, 1);
            targetHeight = Math.Max(targetHeight, 1);
            return new OpenCvSharp. Size(targetWidth, targetHeight);
        }
        private static InterpolationFlags ConvertInterpolation(ResizeInterpolation interpolation)
        {
            return interpolation switch
            {
                ResizeInterpolation.Nearest => InterpolationFlags.Nearest,
                ResizeInterpolation.Linear => InterpolationFlags.Linear,
                ResizeInterpolation.Cubic => InterpolationFlags.Cubic,
                ResizeInterpolation.Area => InterpolationFlags.Area,
                ResizeInterpolation.Lanczos4 => InterpolationFlags.Lanczos4,
                _ => throw new ArgumentOutOfRangeException(nameof(interpolation), interpolation, "Неизвестный режим интерполяции.")
            };
        }
        private static void ValidateParameters(ResizeMode mode, int width, int height, double scalePercent)
        {
            if (!Enum.IsDefined(mode)) throw new ArgumentOutOfRangeException(nameof(mode), mode, "Неизвестный режим изменения размера.");
            if (width < 1 || width > 32768) throw new ArgumentException("Ширина должна быть от 1 до 32768 пикселей.");
            if (height < 1 || height > 32768) throw new ArgumentException("Высота должна быть от 1 до 32768 пикселей.");
            if (double.IsNaN(scalePercent) || double.IsInfinity(scalePercent) || scalePercent < 0.1 || scalePercent > 1000.0)
                throw new ArgumentException("Масштаб должен быть от 0,1 до 1000 процентов.");
        }
    }
}