// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
using osuTK;

namespace osu.Game.Rulesets.Osu.Edit
{
    public partial class FreehandSliderToolboxGroup : EditorToolboxGroup
    {
        public FreehandSliderToolboxGroup()
            : base("freehand")
        {
        }

        public BindableFloat Tolerance { get; } = new BindableFloat(1.8f)
        {
            MinValue = 0.05f,
            MaxValue = 2.0f,
            Precision = 0.01f
        };

        public BindableFloat CornerThreshold { get; } = new BindableFloat(0.4f)
        {
            MinValue = 0.05f,
            MaxValue = 1f,
            Precision = 0.01f
        };

        public BindableFloat CircleThreshold { get; } = new BindableFloat(0.0015f)
        {
            MinValue = 0f,
            MaxValue = 0.005f,
            Precision = 0.0001f
        };

        // We map internal ranges to a more standard range of values for display to the user.
        private readonly BindableInt displayTolerance = new BindableInt(90)
        {
            MinValue = 5,
            MaxValue = 100,
            Precision = 1,
        };

        private readonly BindableInt displayCornerThreshold = new BindableInt(40)
        {
            MinValue = 5,
            MaxValue = 100,
            Precision = 1,
        };

        private readonly BindableInt displayCircleThreshold = new BindableInt(30)
        {
            MinValue = 0,
            MaxValue = 100,
            Precision = 1,
        };

        private ExpandableSlider<int> toleranceSlider = null!;
        private ExpandableSlider<int> cornerThresholdSlider = null!;
        private ExpandableSlider<int> circleThresholdSlider = null!;

        [Resolved]
        private IExpandingContainer? expandingContainer { get; set; }

        [BackgroundDependencyLoader]
        private void load()
        {
            Children = new Drawable[]
            {
                toleranceSlider = new ExpandableSlider<int>
                {
                    Current = displayTolerance,
                    ExpandedLabelText = "Control point spacing",
                },
                cornerThresholdSlider = new ExpandableSlider<int>
                {
                    Current = displayCornerThreshold,
                    ExpandedLabelText = "Corner bias",
                },
                circleThresholdSlider = new ExpandableSlider<int>
                {
                    Current = displayCircleThreshold,
                    ExpandedLabelText = "Perfect curve bias"
                }
            };
        }

        protected override void LoadComplete()
        {
            base.LoadComplete();

            displayTolerance.BindValueChanged(tolerance =>
            {
                toleranceSlider.ContractedLabelText = $"C. P. S.: {tolerance.NewValue:N0}";
                Tolerance.Value = displayToInternalTolerance(tolerance.NewValue);
            }, true);

            displayCornerThreshold.BindValueChanged(threshold =>
            {
                cornerThresholdSlider.ContractedLabelText = $"C. B.: {threshold.NewValue:N0}";
                CornerThreshold.Value = displayToInternalCornerThreshold(threshold.NewValue);
            }, true);

            displayCircleThreshold.BindValueChanged(threshold =>
            {
                circleThresholdSlider.ContractedLabelText = $"P. C. B.: {threshold.NewValue:N0}";
                CircleThreshold.Value = displayToInternalCircleThreshold(threshold.NewValue);
            }, true);

            Tolerance.BindValueChanged(tolerance =>
                displayTolerance.Value = internalToDisplayTolerance(tolerance.NewValue)
            );
            CornerThreshold.BindValueChanged(threshold =>
                displayCornerThreshold.Value = internalToDisplayCornerThreshold(threshold.NewValue)
            );
            CircleThreshold.BindValueChanged(threshold =>
                displayCircleThreshold.Value = internalToDisplayCircleThreshold(threshold.NewValue)
            );

            expandingContainer?.Expanded.BindValueChanged(v =>
            {
                Spacing = v.NewValue ? new Vector2(5) : new Vector2(15);
            }, true);

            float displayToInternalTolerance(float v) => v / 50f;
            int internalToDisplayTolerance(float v) => (int)Math.Round(v * 50f);

            float displayToInternalCornerThreshold(float v) => v / 100f;
            int internalToDisplayCornerThreshold(float v) => (int)Math.Round(v * 100f);

            float displayToInternalCircleThreshold(float v) => v / 20000f;
            int internalToDisplayCircleThreshold(float v) => (int)Math.Round(v * 20000f);
        }
    }
}
