using System;
using OpenCvSharp;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Применяет цветовую карту
    /// к одноканальному изображению.
    /// </summary>
    public sealed class ApplyColorMapExecutor : IImageBlockExecutor
    {
        public string BlockType => "ApplyColorMap";

        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));
            }
            ColorMapMode colorMap = projectManager.GetBlockParameter(block.Id, "ColorMap", ColorMapMode.Jet);
            ValidateInput(input, block);
            ColormapTypes openCvColorMap = GetOpenCvColorMap(colorMap);
            Mat output = new Mat();
            try
            {
                Cv2.ApplyColorMap(input, output, openCvColorMap);
                if (output.Empty())
                {
                    throw new InvalidOperationException($"Блок «{block.Name}» вернул пустое изображение.");
                }
                return output;
            }
            catch
            {
                output.Dispose();
                throw;
            }
        }

        private static void ValidateInput(Mat input, ProjectBlock block)
        {
            if (input.Depth() != MatType.CV_8U)
            {
                throw new InvalidOperationException($"Блок «{block.Name}» принимает только 8-битное изображение.\n\nПолучен тип: {input.Type()}");
            }
            if (input.Channels() != 1)
            {
                throw new InvalidOperationException($"Блок «{block.Name}» принимает одноканальное изображение.\n\nПолучено каналов: {input.Channels()}\n\nПеред цветовой картой добавьте блок «Извлечение канала» или преобразование BGR → Gray.");
            }
        }

        private static ColormapTypes GetOpenCvColorMap(ColorMapMode colorMap)
        {
            return colorMap switch
            {
                ColorMapMode.Autumn => ColormapTypes.Autumn,
                ColorMapMode.Bone => ColormapTypes.Bone,
                ColorMapMode.Jet => ColormapTypes.Jet,
                ColorMapMode.Winter => ColormapTypes.Winter,
                ColorMapMode.Rainbow => ColormapTypes.Rainbow,
                ColorMapMode.Ocean => ColormapTypes.Ocean,
                ColorMapMode.Summer => ColormapTypes.Summer,
                ColorMapMode.Spring => ColormapTypes.Spring,
                ColorMapMode.Cool => ColormapTypes.Cool,
                ColorMapMode.Hsv => ColormapTypes.Hsv,
                ColorMapMode.Pink => ColormapTypes.Pink,
                ColorMapMode.Hot => ColormapTypes.Hot,
                ColorMapMode.Parula => ColormapTypes.Parula,
                ColorMapMode.Magma => ColormapTypes.Magma,
                ColorMapMode.Inferno => ColormapTypes.Inferno,
                ColorMapMode.Plasma => ColormapTypes.Plasma,
                ColorMapMode.Viridis => ColormapTypes.Viridis,
                ColorMapMode.Cividis => ColormapTypes.Cividis,
                ColorMapMode.Twilight => ColormapTypes.Twilight,
                ColorMapMode.TwilightShifted => ColormapTypes.TwilightShifted,
                ColorMapMode.Turbo => ColormapTypes.Turbo,
                ColorMapMode.DeepGreen => ColormapTypes.DeepGreen,
                _ => throw new ArgumentOutOfRangeException(nameof(colorMap), colorMap, "Неизвестная цветовая карта.")
            };
        }
    }
}