using System.Text.RegularExpressions;

namespace Pilz.Plugins.Advanced.UI;

internal class ControlListener(IEnumerable<ControlListenerFeature> features, Control control, bool recursive) : IControlListener
{
    private bool isTracking;

    public bool Recursive => recursive;

    public Control Control => control;

    public IEnumerable<ControlListenerFeature> Features => features;

    internal void Track()
    {
        if (isTracking)
            return;
        Track(control);
        isTracking = true;
    }

    protected void Track(Control control)
    {
        control.Disposed += Control_Disposed;
        control.ControlAdded += Control_ControlAdded;
        control.ControlRemoved += Control_ControlRemoved;

        if (!recursive)
            return;

        foreach (var child in control.Controls)
        {
            if (child is Control childControl)
                Track(childControl);
        }
    }

    private void Control_Disposed(object? sender, EventArgs e)
    {
        if (sender is not Control control)
            return;

        Execute(control, ControlExecuteReason.Dispose, null, false);

        control.Disposed -= Control_Disposed;
        control.ControlAdded -= Control_ControlAdded;
        control.ControlRemoved -= Control_ControlRemoved;
    }

    private void Control_ControlAdded(object? sender, ControlEventArgs e)
    {
        if (sender is not Control control)
            return;

        if (e.Control is not null)
            Track(e.Control);

        Execute(control, ControlExecuteReason.Add, new ControlParameters(e.Control), false);
    }

    private void Control_ControlRemoved(object? sender, ControlEventArgs e)
    {
        if (sender is not Control control)
            return;

        Execute(control, ControlExecuteReason.Remove, new ControlParameters(e.Control), false);
    }

    protected internal void Initialize(PluginFunctionParameter? parameters)
    {
        Execute(ControlExecuteReason.Init, parameters);
    }

    public void Execute(PluginFunctionParameter? parameters)
    {
        Execute(ControlExecuteReason.None, parameters);
    }

    protected void Execute(ControlExecuteReason reason, PluginFunctionParameter? parameter)
    {
        Execute(control, reason, parameter, recursive);
    }

    protected void Execute(Control control, ControlExecuteReason reason, PluginFunctionParameter? parameter, bool recursive)
    {
        execute(control);
        void execute(Control control)
        {
            if (control.Name is string name)
            {
                foreach (var feature in features)
                {
                    if (feature.ControlName is null || feature.ControlNameRegEx && Regex.IsMatch(control.Name, feature.ControlName) || feature.ControlName == control.Name)
                        feature.Execute(control, reason, parameter);
                }
            }

            if (!recursive)
                return;

            foreach (var child in control.Controls)
            {
                if (child is Control childControl)
                    execute(childControl);
            }
        }
    }
}
