using System;
using System.ComponentModel;
namespace OpenCVStudio_v0
{
    public sealed class RotateBlockProperties
    {
        private readonly ProjectManager projectManager; private readonly ProjectBlock projectBlock;
        private double angle; private double scale; private bool expandCanvas; private ResizeInterpolation interpolation; private RotateBorderMode borderMode; private double borderValue;
        public RotateBlockProperties(ProjectManager projectManager, ProjectBlock projectBlock)
        {
            this.projectManager = projectManager ?? throw new ArgumentNullException(nameof(projectManager));
            this.projectBlock = projectBlock ?? throw new ArgumentNullException(nameof(projectBlock));
            angle = projectManager.GetBlockParameter(projectBlock.Id, "Angle", 0.0);
            scale = projectManager.GetBlockParameter(projectBlock.Id, "Scale", 1.0);
            expandCanvas = projectManager.GetBlockParameter(projectBlock.Id, "ExpandCanvas", true);
            interpolation = projectManager.GetBlockParameter(projectBlock.Id, "Interpolation", ResizeInterpolation.Linear);
            borderMode = projectManager.GetBlockParameter(projectBlock.Id, "BorderMode", RotateBorderMode.Constant);
            borderValue = projectManager.GetBlockParameter(projectBlock.Id, "BorderValue", 0.0);
        }
        [Category("Поворот")]
        [DisplayName("Угол, °")]
        [Description("Положительное значение поворачивает изображение против часовой стрелки, отрицательное — по часовой.")]
        public double Angle
        {
            get => angle;
            set
            {
                ValidateFinite(value, "Угол");
                if (Math.Abs(angle - value) < double.Epsilon) return;
                angle = value;
                projectManager.SetBlockParameter(projectBlock.Id, "Angle", value);
            }
        }
        [Category("Поворот")]
        [DisplayName("Масштаб")]
        [Description("Масштаб изображения во время поворота. 1,0 сохраняет исходный масштаб.")]
        public double Scale
        {
            get => scale;
            set
            {
                if (double.IsNaN(value) || double.IsInfinity(value) || value <= 0.0 || value > 100.0)
                    throw new ArgumentOutOfRangeException(nameof(value), value, "Масштаб должен быть больше 0 и не превышать 100.");
                if (Math.Abs(scale - value) < double.Epsilon) return;
                scale = value;
                projectManager.SetBlockParameter(projectBlock.Id, "Scale", value);
            }
        }
        [Category("Поворот")]
        [DisplayName("Расширять холст")]
        [Description("Увеличивает размер результата так, чтобы повёрнутое изображение не обрезалось по краям.")]
        public bool ExpandCanvas
        {
            get => expandCanvas;
            set
            {
                if (expandCanvas == value) return;
                expandCanvas = value;
                projectManager.SetBlockParameter(projectBlock.Id, "ExpandCanvas", value);
            }
        }
        [Category("Качество")]
        [DisplayName("Интерполяция")]
        [Description("Способ вычисления пикселей при повороте. Linear подходит для большинства изображений, Nearest — для бинарных масок.")]
        public ResizeInterpolation Interpolation
        {
            get => interpolation;
            set
            {
                if (!Enum.IsDefined(value)) throw new ArgumentOutOfRangeException(nameof(value), value, "Неизвестный режим интерполяции.");
                if (interpolation == value) return;
                interpolation = value;
                projectManager.SetBlockParameter(projectBlock.Id, "Interpolation", value);
            }
        }
        [Category("Границы")]
        [DisplayName("Заполнение")]
        [Description("Способ заполнения областей, появившихся после поворота.")]
        public RotateBorderMode BorderMode
        {
            get => borderMode;
            set
            {
                if (!Enum.IsDefined(value)) throw new ArgumentOutOfRangeException(nameof(value), value, "Неизвестный режим заполнения границ.");
                if (borderMode == value) return;
                borderMode = value;
                projectManager.SetBlockParameter(projectBlock.Id, "BorderMode", value);
            }
        }
        [Category("Границы")]
        [DisplayName("Значение фона")]
        [Description("Значение заполнения границ в режиме Constant. 0 — чёрный, 255 — белый.")]
        public double BorderValue
        {
            get => borderValue;
            set
            {
                ValidateFinite(value, "Значение фона");
                if (value < 0.0 || value > 255.0) throw new ArgumentOutOfRangeException(nameof(value), value, "Значение фона должно быть от 0 до 255.");
                if (Math.Abs(borderValue - value) < double.Epsilon) return;
                borderValue = value;
                projectManager.SetBlockParameter(projectBlock.Id, "BorderValue", value);
            }
        }
        [Category("Блок")]
        [DisplayName("Название")]
        [ReadOnly(true)]
        public string BlockName => projectBlock.Name;
        [Category("Блок")]
        [DisplayName("Тип")]
        [ReadOnly(true)]
        public string BlockType => projectBlock.BlockType;
        [Category("Блок")]
        [DisplayName("Позиция")]
        [ReadOnly(true)]
        public int Position => projectBlock.Order + 1;
        private static void ValidateFinite(double value, string parameterName)
        {
            if (double.IsNaN(value) || double.IsInfinity(value))
                throw new ArgumentException($"{parameterName} содержит недопустимое значение.");
        }
    }
}