using System.Reflection;
using System.Windows.Input;

namespace Gready_Poang.Common;
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
    public required string EventName { get; set; }

    public static readonly BindableProperty CommandProperty =
        BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(EventToCommandBehavior));

    public ICommand Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    // Fix for CS8618: Make the field nullable and fix IDE1006: Add '_' prefix
    private EventInfo? _eventInfo;
    private Delegate? _eventHandler;

    protected override void OnAttachedTo(VisualElement bindable)
    {
        base.OnAttachedTo(bindable);

        if (bindable == null || string.IsNullOrEmpty(EventName))
            return;

        var runtimeEvent = bindable.GetType().GetRuntimeEvent(EventName);
        if (runtimeEvent == null)
            throw new ArgumentException($"Event '{EventName}' not found on type '{bindable.GetType().Name}'");

        _eventInfo = runtimeEvent;

        MethodInfo? methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod(nameof(OnEvent));
        if (methodInfo == null)
            throw new InvalidOperationException($"Method '{nameof(OnEvent)}' not found on type '{typeof(EventToCommandBehavior).Name}'");

        if (_eventInfo.EventHandlerType == null)
            throw new InvalidOperationException($"EventHandlerType for event '{EventName}' is null on type '{bindable.GetType().Name}'");

        _eventHandler = methodInfo.CreateDelegate(_eventInfo.EventHandlerType, this);
        _eventInfo.AddEventHandler(bindable, _eventHandler);
    }

    protected override void OnDetachingFrom(VisualElement bindable)
    {
        base.OnDetachingFrom(bindable);

        if (_eventInfo != null && _eventHandler != null)
            _eventInfo.RemoveEventHandler(bindable, _eventHandler);
    }

    private void OnEvent(object sender, object eventArgs)
    {
        if (Command?.CanExecute(eventArgs) == true)
            Command.Execute(eventArgs);
    }
}
