using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Xaml.Behaviors;

namespace InABox.WPF;

public class TextBoxPlaceholderBehaviour : Behavior<TextBox>
{
        
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
            nameof(Text),
            typeof(String),
            typeof(TextBoxPlaceholderBehaviour),
            new PropertyMetadata(""));

    public String Text
    {
        get => (String)GetValue(TextProperty);
        set
        {
            SetValue(TextProperty, value);
            UpdateAssociatedObject(true);
        }
    }
        
    public static readonly DependencyProperty TextColorProperty =
        DependencyProperty.Register(
            nameof(TextColor),
            typeof(System.Windows.Media.Color),
            typeof(TextBoxPlaceholderBehaviour),
            new PropertyMetadata(Colors.Gray));

    public System.Windows.Media.Color TextColor
    {
        get => (System.Windows.Media.Color)GetValue(TextColorProperty);
        set
        {
            SetValue(TextColorProperty, value);
            UpdateAssociatedObject(true);
        }
    }
        
    private readonly PropertyDescriptor _propertyDescriptor = 
        DependencyPropertyDescriptor.FromProperty(TextBox.BackgroundProperty, typeof(TextBox));
        
    private Brush? _originalBackground;
    private Brush? _placeholderBackground;
        
    protected override void OnAttached()
    {
        base.OnAttached();

        // Store the Background that has been set on the Text Box (usu through XAML)
        _originalBackground = AssociatedObject.Background;
            
        // Start Monitoring changes to the Associated object Background property
        _propertyDescriptor.AddValueChanged(AssociatedObject, OnBackgroundChanged);
            
        AssociatedObject.TextChanged += OnTextChanged;
        AssociatedObject.SizeChanged += OnSizeChanged;
            
        UpdateAssociatedObject();
    }
        
    protected override void OnDetaching()
    {
        AssociatedObject.SizeChanged -= OnSizeChanged;
        AssociatedObject.TextChanged -= OnTextChanged;

        _propertyDescriptor?.RemoveValueChanged(AssociatedObject,OnBackgroundChanged);

        AssociatedObject.Background = _originalBackground;
            
        base.OnDetaching();
    }
        
        
    private void OnBackgroundChanged(object? sender, EventArgs e)
    {
        // Update the Saved Background (usu a color, but might not be?)
        _originalBackground = AssociatedObject.Background;
        UpdateAssociatedObject(true);
    }

    private void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        UpdateAssociatedObject();
    }

    private void SetBackground(Brush? brush)
    {
        _propertyDescriptor.RemoveValueChanged(AssociatedObject, OnBackgroundChanged);
        AssociatedObject.Background = brush;
        _propertyDescriptor.AddValueChanged(AssociatedObject, OnBackgroundChanged);
    }
        
    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        UpdateAssociatedObject(true);
    }
        
    private Brush CreatePlaceholder()
    {
        return new VisualBrush()
        {
            Visual = new Label()
            {
                Content = Text,
                Margin = new(0.0),
                Padding = new Thickness(4 + AssociatedObject.Padding.Left, 0 + AssociatedObject.Padding.Top, 2 + AssociatedObject.Padding.Right, 0 + AssociatedObject.Padding.Bottom),
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch,
                HorizontalContentAlignment = AssociatedObject.HorizontalContentAlignment,
                VerticalContentAlignment = AssociatedObject.VerticalContentAlignment,
                FontFamily = AssociatedObject.FontFamily,
                FontStretch = AssociatedObject.FontStretch,
                FontSize = AssociatedObject.FontSize,
                FontWeight = AssociatedObject.FontWeight,
                FontStyle = FontStyles.Italic,
                Background = _originalBackground?.Clone(),
                Foreground = new SolidColorBrush(TextColor),
                Width = AssociatedObject.ActualWidth,
                Height = AssociatedObject.ActualHeight
            },
            Stretch = Stretch.None,
            TileMode = TileMode.None,
            AlignmentX = AlignmentX.Left,
            AlignmentY = AlignmentY.Center
        };
    }
        
    private void UpdateAssociatedObject(bool force = false)
    {
        if (AssociatedObject is null) return;

        if (force)
            _placeholderBackground = null;
        
        if (String.IsNullOrWhiteSpace(AssociatedObject.Text) && _placeholderBackground == null)
        {
            _placeholderBackground = CreatePlaceholder();
            SetBackground(_placeholderBackground);
        }
        else if (!String.IsNullOrWhiteSpace(AssociatedObject.Text) && _placeholderBackground != null)
        { 
            _placeholderBackground = null;
            SetBackground(_originalBackground);
        }
    }
}