using System;
using OpenCvSharp;

namespace OpenCVStudio_v0
{
    public sealed class LutExecutor : IImageBlockExecutor
    {
        public string BlockType => "Lut";

        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            if (input == null)
                throw new ArgumentNullException(nameof(input));
            if (input.Empty())
                throw new InvalidOperationException("LUT: входное изображение пустое.");
            LutMode mode = projectManager.GetBlockParameter(block.Id, "Mode", LutMode.Identity);
            double gamma = projectManager.GetBlockParameter(block.Id, "Gamma", 1.0);
            int threshold = projectManager.GetBlockParameter(block.Id, "Threshold", 128);
            using Mat lut = CreateLut(mode, gamma, threshold);
            Mat result = new Mat();
            Cv2.LUT(input, lut, result);
            return result;
        }

        private static Mat CreateLut(LutMode mode, double gamma, int threshold)
        {
            Mat lut = new Mat(1, 256, MatType.CV_8UC1);
            for (int i = 0; i < 256; i++)
            {
                byte value;
                switch (mode)
                {
                    case LutMode.Invert:
                        value = (byte)(255 - i);
                        break;
                    case LutMode.Gamma:
                        value = (byte)(Math.Clamp(Math.Pow(i / 255.0, gamma) * 255.0, 0, 255));
                        break;
                    case LutMode.Threshold:
                        value = (byte)(i >= threshold ? 255 : 0);
                        break;
                    default:
                        value = (byte)i;
                        break;
                }
                lut.Set(0, i, value);
            }
            return lut;
        }
    }
}