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

using OpenCvSharp;
namespace OpenCVStudio_v0
{
    public sealed class SimpleThresholdExecutor : IImageBlockExecutor
    {
        public string BlockType => "SimpleThreshold";
        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(input);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (input.Empty()) throw new ArgumentException("В SimpleThreshold передано пустое изображение.", nameof(input));
            double thresholdValue = projectManager.GetBlockParameter(block.Id, "ThresholdValue", 128.0);
            double maxValue = projectManager.GetBlockParameter(block.Id, "MaxValue", 255.0);
            SimpleThresholdType thresholdType = projectManager.GetBlockParameter(block.Id, "ThresholdType", SimpleThresholdType.Binary);
            using Mat grayInput = PrepareGrayInput(input);
            ThresholdTypes openCvThresholdType = ConvertThresholdType(thresholdType);
            Mat output = new Mat();
            try
            {
                Cv2.Threshold(grayInput, output, thresholdValue, maxValue, openCvThresholdType);
                if (output.Empty()) throw new InvalidOperationException("SimpleThreshold вернул пустое изображение.");
                return output;
            }
            catch { output.Dispose(); throw; }
        }
        private static Mat PrepareGrayInput(Mat input)
        {
            if (input.Channels() == 1) return input.Clone();
            if (input.Channels() == 3)
            {
                Mat gray = new Mat();
                Cv2.CvtColor(input, gray, ColorConversionCodes.BGR2GRAY);
                return gray;
            }
            if (input.Channels() == 4)
            {
                Mat gray = new Mat();
                Cv2.CvtColor(input, gray, ColorConversionCodes.BGRA2GRAY);
                return gray;
            }
            throw new NotSupportedException($"SimpleThreshold не поддерживает изображение с числом каналов: {input.Channels()}.");
        }
        private static ThresholdTypes ConvertThresholdType(SimpleThresholdType thresholdType)
        {
            return thresholdType switch
            {
                SimpleThresholdType.Binary => ThresholdTypes.Binary,
                SimpleThresholdType.BinaryInv => ThresholdTypes.BinaryInv,
                SimpleThresholdType.Trunc => ThresholdTypes.Trunc,
                SimpleThresholdType.ToZero => ThresholdTypes.Tozero,
                SimpleThresholdType.ToZeroInv => ThresholdTypes.TozeroInv,
                SimpleThresholdType.Otsu => ThresholdTypes.Binary | ThresholdTypes.Otsu,
                SimpleThresholdType.Triangle => ThresholdTypes.Binary | ThresholdTypes.Triangle,
                _ => throw new ArgumentOutOfRangeException(nameof(thresholdType), thresholdType, "Неизвестный тип порога.")
            };
        }
    }
}