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

using System;
using OpenCvSharp;
namespace OpenCVStudio_v0
{
    public sealed class EqualizeHistExecutor : IImageBlockExecutor
    {
        public string BlockType => "EqualizeHist";
        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(input);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (input.Empty()) throw new ArgumentException("В EqualizeHist передано пустое изображение.", nameof(input));
            bool convertToGray = projectManager.GetBlockParameter(block.Id, "ConvertToGray", true);
            using Mat grayInput = PrepareGrayInput(input, convertToGray);
            Mat output = new Mat();
            try
            {
                Cv2.EqualizeHist(grayInput, output);
                if (output.Empty()) throw new InvalidOperationException("EqualizeHist вернул пустое изображение.");
                return output;
            }
            catch { output.Dispose(); throw; }
        }
        private static Mat PrepareGrayInput(Mat input, bool convertToGray)
        {
            if (input.Channels() == 1) return EnsureByteImage(input);
            if (!convertToGray) throw new InvalidOperationException("EqualizeHist работает только с одноканальным изображением. Включите параметр «Преобразовать в серое» или добавьте перед ним блок цветового канала.");
            Mat gray = new Mat();
            try
            {
                switch (input.Channels())
                {
                    case 3:
                        Cv2.CvtColor(input, gray, ColorConversionCodes.BGR2GRAY);
                        break;
                    case 4:
                        Cv2.CvtColor(input, gray, ColorConversionCodes.BGRA2GRAY);
                        break;
                    default:
                        throw new NotSupportedException($"EqualizeHist не поддерживает изображение с количеством каналов: {input.Channels()}.");
                }
                if (gray.Type() == MatType.CV_8UC1) return gray;
                Mat converted = new Mat();
                try
                {
                    gray.ConvertTo(converted, MatType.CV_8UC1);
                    return converted;
                }
                catch { converted.Dispose(); throw; }
                finally { gray.Dispose(); }
            }
            catch { gray.Dispose(); throw; }
        }
        private static Mat EnsureByteImage(Mat input)
        {
            if (input.Type() == MatType.CV_8UC1) return input.Clone();
            Mat converted = new Mat();
            try
            {
                input.ConvertTo(converted, MatType.CV_8UC1);
                return converted;
            }
            catch { converted.Dispose(); throw; }
        }
    }
}