using System;
using System.Linq;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Interactivity;

namespace Inspectron.Settings.Avalonia.Configuration;

public partial class ItemEditorDialog : Window
{
    private readonly Type _itemType;
    private object? _workingValue;
    private readonly DefaultControlFactory _controlFactory;
    private readonly OptionsWindow _parentOptionsWindow;

    public ItemEditorDialog(Type itemType, object? initialValue, DefaultControlFactory controlFactory, OptionsWindow parentOptionsWindow)
    {
        _itemType = itemType;
        _workingValue = CloneObject(initialValue);
        _controlFactory = controlFactory;
        _parentOptionsWindow = parentOptionsWindow;

        InitializeComponent();
        Title = $"Edit {_itemType.Name}";

        CreatePropertyControls();

        BtnOK.Click += BtnOK_Click;
        BtnCancel.Click += BtnCancel_Click;
    }

    private void CreatePropertyControls()
    {
        if (_itemType.IsValueType || _itemType == typeof(string))
        {
            CreateSimpleValueControl();
        }
        else
        {
            CreateComplexObjectControls();
        }
    }

    private void CreateSimpleValueControl()
    {
        var dummyProperty = new SimplePropertyInfo(_itemType, "Value");
        var control = _controlFactory.CreateControl("Value", "Value", dummyProperty, _workingValue!,
            newValue => _workingValue = newValue, _parentOptionsWindow);

        PropertyPanel.Children.Add(control);
    }

    private void CreateComplexObjectControls()
    {
        var properties = _itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.CanRead && p.CanWrite)
            .ToArray();

        foreach (var property in properties)
        {
            var currentValue = property.GetValue(_workingValue);
            var control = _controlFactory.CreateControl(property.Name, property.Name, property, currentValue!,
                newValue => property.SetValue(_workingValue, newValue), _parentOptionsWindow);

            PropertyPanel.Children.Add(control);
        }
    }

    private void BtnOK_Click(object? sender, RoutedEventArgs e)
    {
        Close(_workingValue);
    }

    private void BtnCancel_Click(object? sender, RoutedEventArgs e)
    {
        Close(null);
    }

    private object? CloneObject(object? obj)
    {
        if (obj == null) return GetDefaultValue(_itemType);

        var type = obj.GetType();
        if (type.IsValueType || type == typeof(string))
        {
            return obj;
        }

        try
        {
            var clone = Activator.CreateInstance(type);
            foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (prop.CanRead && prop.CanWrite)
                {
                    prop.SetValue(clone, prop.GetValue(obj));
                }
            }
            return clone;
        }
        catch
        {
            return GetDefaultValue(type);
        }
    }

    private object? GetDefaultValue(Type type)
    {
        if (type.IsValueType)
        {
            return Activator.CreateInstance(type);
        }
        else if (type == typeof(string))
        {
            return "";
        }
        else
        {
            try
            {
                return Activator.CreateInstance(type);
            }
            catch
            {
                return null;
            }
        }
    }
}
