using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;

namespace PCL;

[ContentProperty("Inlines")]
public partial class MyCheckBox
{
    public delegate void ChangeEventHandler(object sender, bool user);

    public delegate void PreviewChangeEventHandler(object sender, ModBase.RouteEventArgs e);

    private const int animationTimeOfCheck = 150; // 勾选状态变更动画长度

    // 指向动画

    private const int animationTimeOfMouseIn = 100;

    private const int animationTimeOfMouseOut = 200;

    // 在使用 XAML 设置 Checked 属性时，不会触发 Checked_Set 方法，所以需要在这里手动触发 UI 改变
    public static readonly DependencyProperty CheckedProperty = DependencyProperty.Register("Checked", typeof(bool?),
        typeof(MyCheckBox), new PropertyMetadata(false, (d, e) =>
        {
            var obj = (MyCheckBox)d;
            if (!obj.IsLoaded) obj.SyncUI();
        }));

    /// <summary>
    ///     是否为三态复选框。
    /// </summary>
    public static readonly DependencyProperty IsThreeStateProperty =
        DependencyProperty.Register("IsThreeState", typeof(bool), typeof(MyCheckBox), new PropertyMetadata(false));

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string),
        typeof(MyCheckBox), new PropertyMetadata((sender, e) =>
        {
            if (sender is not null) ((MyCheckBox)sender).LabText.Text = (string)e.NewValue;
        }));

    private bool? _previousState = false; // 上一次的勾选状态
    private bool allowMouseDown = true;

    // 点击事件

    private bool mouseDowned;

    // 基础

    public int Uuid = ModBase.GetUuid();

    public MyCheckBox()
    {
        InitializeComponent();

        MouseLeftButtonUp += (_, _) => Checkbox_MouseUp();
        MouseLeftButtonDown += (_, _) => Checkbox_MouseDown();
        MouseLeave += (_, _) => Checkbox_MouseLeave();
        IsEnabledChanged += (_, _) => Checkbox_IsEnabledChanged();
        MouseEnter += (_, _) => Checkbox_MouseEnterAnimation();
        MouseLeave += (_, _) => Checkbox_MouseLeaveAnimation();
    }

    // 自定义属性
    public bool? Checked
    {
        get => (bool?)GetValue(CheckedProperty);
        set => SetChecked(value, false);
    }

    public bool IsThreeState
    {
        get => (bool)GetValue(IsThreeStateProperty);
        set => SetValue(IsThreeStateProperty, value);
    } // 是否为三态复选框

    public InlineCollection Inlines => LabText.Inlines;

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    } // 内容

    /// <summary>
    ///     复选框勾选状态改变。
    /// </summary>
    /// <param name="user">是否为用户手动改变的勾选状态。</param>
    public event ChangeEventHandler? Change;

    public event PreviewChangeEventHandler? PreviewChange;

    /// <summary>
    ///     手动设置 Checked 属性。
    /// </summary>
    /// <param name="value">新的 Checked 属性。</param>
    /// <param name="user">是否由用户引发。</param>
    public void SetChecked(bool? value, bool user)
    {
        try
        {
            if (Checked.HasValue && value.HasValue && Checked.Value == value.Value)
                return;

            // Preview 事件
            if (value.HasValue && value.Value && user)
            {
                var e = new ModBase.RouteEventArgs(user);
                PreviewChange?.Invoke(this, e);
                if (e.handled)
                {
                    mouseDowned = true;
                    Checkbox_MouseLeave();
                    mouseDowned = false;
                    return;
                }
            }

            // 判断真实勾选状态
            var isChecked = GetFinalState(value, IsThreeState);

            _previousState = Checked; // 记录上一次的勾选状态
            SetValue(CheckedProperty, isChecked);
            if (IsLoaded)
                Change?.Invoke(this, user);

            // 更改动画
            SyncUI();
            ModMain.RaiseCustomEvent(this);
        }
        catch (Exception ex)
        {
            ModBase.Log(ex, "设置 Checked 失败");
        }
    }

    private void SyncUI()
    {
        if (ControlVisualHelpers.ShouldAnimate(this)) // 防止默认属性变更触发动画
        {
            allowMouseDown = false;

            var isChecked = GetFinalState(Checked, IsThreeState);

            switch (isChecked, _previousState)
            {
                case (true, null):
                    AniBackgroundScale();
                    AniIndeterminateHide();
                    AniCheckShow();
                    AniColorChecked();
                    AniAllowMouseDown();
                    break;

                case (true, false):
                    AniBackgroundScale();
                    AniCheckShow();
                    AniColorChecked();
                    AniAllowMouseDown();
                    break;

                case (false, true):
                    AniBackgroundScale();
                    AniCheckHide();
                    AniColorUnchecked();
                    AniAllowMouseDown();
                    break;

                case (false, null):
                    AniBackgroundScale();
                    AniIndeterminateHide();
                    AniCheckHide();
                    AniColorUnchecked();
                    AniAllowMouseDown();
                    break;

                case (null, true):
                    AniBackgroundScale();
                    AniCheckHide();
                    AniIndeterminateShow();
                    AniColorUnchecked();
                    AniAllowMouseDown();
                    break;

                case (null, false):
                    AniBackgroundScale();
                    AniIndeterminateShow();
                    AniColorUnchecked();
                    AniAllowMouseDown();
                    break;
            }
        }
        else
        {
            // 不使用动画
            ModAnimation.AniStop("MyCheckBox Background Scale " + Uuid);
            ModAnimation.AniStop("MyCheckBox Check Scale Show" + Uuid);
            ModAnimation.AniStop("MyCheckBox Check Scale Hide" + Uuid);
            ModAnimation.AniStop("MyCheckBox Indeterminate Scale Show" + Uuid);
            ModAnimation.AniStop("MyCheckBox Indeterminate Scale Hide" + Uuid);
            ModAnimation.AniStop("MyCheckBox BorderColor " + Uuid);
            ModAnimation.AniStop("MyCheckBox AllowMouseDown " + Uuid);
            if (Checked == true)
            {
                ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX = 1d;
                ((ScaleTransform)ShapeCheck.RenderTransform).ScaleY = 1d;
                ShapeBorder.SetResourceReference(Border.BorderBrushProperty,
                    IsEnabled ? "ColorBrush2" : "ColorBrushGray4");
            }
            else
            {
                ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX = 0d;
                ((ScaleTransform)ShapeCheck.RenderTransform).ScaleY = 0d;
                ShapeBorder.SetResourceReference(Border.BorderBrushProperty,
                    IsEnabled ? "ColorBrush1" : "ColorBrushGray4");
            }
        }
    }

    private void Checkbox_MouseUp()
    {
        if (!mouseDowned)
            return;
        ModBase.Log("[Control] 按下复选框（" + !Checked + "）：" + Text);
        mouseDowned = false;
        if (IsThreeState)
        {
            switch (Checked)
            {
                case true:
                    SetChecked(null, true);
                    break;
                case false:
                    SetChecked(true, true);
                    break;
                case null:
                    SetChecked(false, true);
                    break;
            }

            ModAnimation.AniStart(
                ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100),
                "MyCheckBox Background " + Uuid);
            return;
        }

        SetChecked(!Checked, true);
        ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100),
            "MyCheckBox Background " + Uuid);
    }

    private void Checkbox_MouseDown()
    {
        if (!allowMouseDown)
            return;
        mouseDowned = true;
        Focus();
        ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushBg1", 100),
            "MyCheckBox Background " + Uuid);
        var scaleAnims = new List<ModAnimation.AniData>
        {
            ModAnimation.AaScale(ShapeBorder, 16.5d - ShapeBorder.Width, 1000,
                ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong), absolute: true)
        };
        if (Checked == true)
            scaleAnims.Add(ModAnimation.AaScaleTransform(ShapeCheck,
                0.9d - ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX, 1000,
                ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)));
        ModAnimation.AniStart(scaleAnims.ToArray(), "MyCheckBox Scale " + Uuid);
    }

    private void Checkbox_MouseLeave()
    {
        if (!mouseDowned)
            return;
        mouseDowned = false;
        ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100),
            "MyCheckBox Background " + Uuid);
        var scaleAnims = new List<ModAnimation.AniData>
        {
            ModAnimation.AaScale(ShapeBorder, 18d - ShapeBorder.Width,
                ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong), absolute: true)
        };
        if (Checked == true)
            scaleAnims.Add(ModAnimation.AaScaleTransform(ShapeCheck, 1d - ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX,
                500, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Strong)));
        ModAnimation.AniStart(scaleAnims.ToArray(), "MyCheckBox Scale " + Uuid);
    }

    private void Checkbox_IsEnabledChanged()
    {
        if (IsLoaded && ModAnimation.AniControlEnabled == 0) // 防止默认属性变更触发动画
        {
            // 有动画
            if (IsEnabled)
            {
                // 可用
                Checkbox_MouseLeaveAnimation();
            }
            else
            {
                // 不可用
                ModAnimation.AniStart(
                    ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
                        ThemeManager.colorGray4 - ShapeBorder.BorderBrush, animationTimeOfMouseOut),
                    "MyCheckBox BorderColor " + Uuid);
                ModAnimation.AniStart(
                    ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty,
                        ThemeManager.colorGray4 - LabText.Foreground, animationTimeOfMouseOut),
                    "MyCheckBox TextColor " + Uuid);
            }
        }
        else
        {
            // 无动画
            ModAnimation.AniStop("MyCheckBox TextColor " + Uuid);
            ModAnimation.AniStop("MyCheckBox BorderColor " + Uuid);
            LabText.SetResourceReference(TextBlock.ForegroundProperty, IsEnabled ? "ColorBrush1" : "ColorBrushGray4");
            ShapeBorder.SetResourceReference(Border.BorderBrushProperty,
                IsEnabled ? Checked == true ? "ColorBrush2" : "ColorBrush1" : "ColorBrushGray4");
        }
    }

    private void Checkbox_MouseEnterAnimation()
    {
        ModAnimation.AniStart(
            ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", animationTimeOfMouseIn),
            "MyCheckBox TextColor " + Uuid);
        ModAnimation.AniStart(
            ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty, "ColorBrush3", animationTimeOfMouseIn),
            "MyCheckBox BorderColor " + Uuid);
    }

    private void Checkbox_MouseLeaveAnimation()
    {
        if (!IsEnabled)
            return; // MouseLeave 比 IsEnabledChanged 后执行，所以如果自定义事件修改了 IsEnabled，将导致显示错误
        ModAnimation.AniStart(
            ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty,
                IsEnabled ? "ColorBrush1" : "ColorBrushGray4", animationTimeOfMouseOut),
            "MyCheckBox TextColor " + Uuid);
        ModAnimation.AniStart(
            ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
                IsEnabled ? Checked == true ? "ColorBrush2" : "ColorBrush1" : "ColorBrushGray4",
                animationTimeOfMouseOut),
            "MyCheckBox BorderColor " + Uuid);
    }

    // 动画
    private void AniBackgroundScale()
    {
        ModAnimation.AniStart(
            new[]
            {
                ModAnimation.AaScale(ShapeBorder, 12d - ShapeBorder.Width, animationTimeOfCheck,
                    ease: new ModAnimation.AniEaseOutFluent(), absolute: true),
                ModAnimation.AaScale(ShapeBorder, 6d, animationTimeOfCheck * 2,
                    (int)Math.Round(animationTimeOfCheck * 0.7d), new ModAnimation.AniEaseOutBack(), absolute: true)
            }, "MyCheckBox Background Scale " + Uuid);
    }

    private void AniCheckShow()
    {
        ModAnimation.AniStart(
            ModAnimation.AaScaleTransform(ShapeCheck, 1d - ((ScaleTransform)ShapeCheck.RenderTransform).ScaleX,
                animationTimeOfCheck * 2, (int)Math.Round(animationTimeOfCheck * 0.7d),
                new ModAnimation.AniEaseOutBack(ModAnimation.AniEasePower.Weak)),
            "MyCheckBox Check Scale Show" + Uuid);
    }

    private void AniCheckHide()
    {
        ModAnimation.AniStart(
            ModAnimation.AaScaleTransform(ShapeCheck, -((ScaleTransform)ShapeCheck.RenderTransform).ScaleX,
                (int)Math.Round(animationTimeOfCheck * 0.9d),
                ease: new ModAnimation.AniEaseInFluent(ModAnimation.AniEasePower.Weak)),
            "MyCheckBox Check Scale Hide" + Uuid);
    }

    private void AniIndeterminateShow()
    {
        ModAnimation.AniStart(
            ModAnimation.AaScaleTransform(ShapeIndeterminate,
                1d - ((ScaleTransform)ShapeIndeterminate.RenderTransform).ScaleX, animationTimeOfCheck * 2,
                (int)Math.Round(animationTimeOfCheck * 0.7d),
                new ModAnimation.AniEaseOutBack(ModAnimation.AniEasePower.Weak)),
            "MyCheckBox Indeterminate Scale Show" + Uuid);
    }

    private void AniIndeterminateHide()
    {
        ModAnimation.AniStart(
            ModAnimation.AaScaleTransform(ShapeIndeterminate,
                -((ScaleTransform)ShapeIndeterminate.RenderTransform).ScaleX,
                (int)Math.Round(animationTimeOfCheck * 0.9d),
                ease: new ModAnimation.AniEaseInFluent(ModAnimation.AniEasePower.Weak)),
            "MyCheckBox Indeterminate Scale Hide" + Uuid);
    }

    private void AniAllowMouseDown()
    {
        ModAnimation.AniStart(ModAnimation.AaCode(() => allowMouseDown = true, animationTimeOfCheck * 2),
            "MyCheckBox AllowMouseDown " + Uuid);
    }

    private void AniColorChecked()
    {
        ModAnimation.AniStart(
            ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
                IsEnabled ? IsMouseOver ? "ColorBrush3" : "ColorBrush2" : "ColorBrushGray4", animationTimeOfCheck),
            "MyCheckBox BorderColor " + Uuid);
    }

    private void AniColorUnchecked()
    {
        ModAnimation.AniStart(
            ModAnimation.AaColor(ShapeBorder, Border.BorderBrushProperty,
                IsEnabled ? IsMouseOver ? "ColorBrush3" : "ColorBrush1" : "ColorBrushGray4", animationTimeOfCheck),
            "MyCheckBox BorderColor " + Uuid);
    }

    private static bool? GetFinalState(bool? value, bool isThreeState)
    {
        return isThreeState ? value : value == true;
    }
}
