using System;
using System.ComponentModel;

namespace OpenCVStudio_v0
{
    public sealed class PhaseBlockProperties
    {
        private readonly ProjectManager projectManager;
        private readonly ProjectBlock block;
        private int kernelSize;
        private bool useBlur;
        private int blurSize;
        private double scale;
        private bool angleInDegrees;

        public PhaseBlockProperties(ProjectManager projectManager, ProjectBlock block)
        {
            this.projectManager = projectManager ?? throw new ArgumentNullException(nameof(projectManager));
            this.block = block ?? throw new ArgumentNullException(nameof(block));
            kernelSize = projectManager.GetBlockParameter(block.Id, "KernelSize", 3);
            useBlur = projectManager.GetBlockParameter(block.Id, "UseBlur", true);
            blurSize = projectManager.GetBlockParameter(block.Id, "BlurSize", 3);
            scale = projectManager.GetBlockParameter(block.Id, "Scale", 1.0);
            angleInDegrees = projectManager.GetBlockParameter(block.Id, "AngleInDegrees", true);
        }

        [Category("Sobel")]
        [DisplayName("Размер ядра")]
        [Description("Нечётный размер ядра Sobel: 1, 3, 5 или 7.")]
        public int KernelSize
        {
            get => kernelSize;
            set
            {
                kernelSize = NormalizeSobelKernelSize(value);
                Save("KernelSize", kernelSize);
            }
        }

        [Category("Sobel")]
        [DisplayName("Масштаб")]
        [Description("Множитель производных Sobel.")]
        public double Scale
        {
            get => scale;
            set
            {
                scale = value;
                Save("Scale", scale);
            }
        }

        [Category("Подготовка")]
        [DisplayName("Предварительное размытие")]
        [Description("Применить GaussianBlur перед вычислением градиентов.")]
        public bool UseBlur
        {
            get => useBlur;
            set
            {
                useBlur = value;
                Save("UseBlur", useBlur);
            }
        }

        [Category("Подготовка")]
        [DisplayName("Размер размытия")]
        [Description("Нечётный размер ядра GaussianBlur.")]
        public int BlurSize
        {
            get => blurSize;
            set
            {
                blurSize = NormalizeOddSize(value, minimum: 1);
                Save("BlurSize", blurSize);
            }
        }

        [Category("Результат")]
        [DisplayName("Угол в градусах")]
        [Description("True: диапазон 0–360°. False: диапазон 0–2π радиан. Для отображения оба варианта преобразуются в диапазон 0–255.")]
        public bool AngleInDegrees
        {
            get => angleInDegrees;
            set
            {
                angleInDegrees = value;
                Save("AngleInDegrees", angleInDegrees);
            }
        }

        [Category("Блок")]
        [DisplayName("Название")]
        [ReadOnly(true)]
        public string Name => block.Name;

        [Category("Блок")]
        [DisplayName("Тип")]
        [ReadOnly(true)]
        public string BlockType => block.BlockType;

        private void Save(string parameterName, object value)
        {
            projectManager.SetBlockParameter(block.Id, parameterName, value);
        }

        private static int NormalizeSobelKernelSize(int value)
        {
            if (value <= 1) return 1;
            if (value <= 3) return 3;
            if (value <= 5) return 5;
            return 7;
        }

        private static int NormalizeOddSize(int value, int minimum)
        {
            int normalized = Math.Max(minimum, value);
            if (normalized % 2 == 0) normalized++;
            return normalized;
        }
    }
}