using System;
using OpenCvSharp;
using OpenCvSharp.XImgProc;

namespace OpenCVStudio_v0
{
    /// <summary>
    /// Формирует однопиксельный скелет бинарных объектов.
    /// </summary>
    public sealed class ThinningExecutor : IImageBlockExecutor
    {
        public string BlockType => "Thinning";

        public Mat Execute(Mat input, ProjectBlock block, ProjectManager projectManager)
        {
            ArgumentNullException.ThrowIfNull(input);
            ArgumentNullException.ThrowIfNull(block);
            ArgumentNullException.ThrowIfNull(projectManager);
            if (input.Empty())
            {
                throw new ArgumentException("В блок Thinning передано пустое изображение.", nameof(input));
            }
            ValidateInput(input, block);
            ThinningAlgorithmMode algorithm = projectManager.GetBlockParameter(block.Id, "Algorithm", ThinningAlgorithmMode.ZhangSuen);
            ThinningTypes thinningType = ConvertAlgorithm(algorithm);
            Mat output = new Mat();
            try
            {
                CvXImgProc.Thinning(input, output, thinningType);
                if (output.Empty())
                {
                    throw new InvalidOperationException($"Блок «{block.Name}» вернул пустое изображение.");
                }
                return output;
            }
            catch
            {
                output.Dispose();
                throw;
            }
        }

        private static void ValidateInput(Mat input, ProjectBlock block)
        {
            if (input.Type() != MatType.CV_8UC1)
            {
                throw new InvalidOperationException($"Блок «{block.Name}»: скелетизация поддерживает только одноканальную бинарную маску CV_8UC1.");
            }
        }

        private static ThinningTypes ConvertAlgorithm(ThinningAlgorithmMode algorithm)
        {
            return algorithm switch
            {
                ThinningAlgorithmMode.ZhangSuen => ThinningTypes.ZHANGSUEN,
                ThinningAlgorithmMode.GuoHall => ThinningTypes.GUOHALL,
                _ => throw new ArgumentOutOfRangeException(nameof(algorithm), algorithm, "Неизвестный алгоритм скелетизации.")
            };
        }
    }
}