using System;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace Inspectron.Settings.Windows.Configuration;

public partial class ItemEditorDialog : Form
{
    private readonly Type _itemType;
    private object _workingValue;
    private readonly DefaultControlFactory _controlFactory;
    private readonly OptionsWindow _parentOptionsWindow;
    
    private FlowLayoutPanel _propertyPanel;
    private Button _okButton;
    private Button _cancelButton;

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

    private void InitializeComponent()
    {
        this.Text = $"Edit {_itemType.Name}";
        this.Size = new System.Drawing.Size(650, 420);
        this.StartPosition = FormStartPosition.CenterParent;
        this.FormBorderStyle = FormBorderStyle.FixedDialog;
        this.MaximizeBox = false;
        this.MinimizeBox = false;

        _propertyPanel = new FlowLayoutPanel
        {
            Location = new System.Drawing.Point(12, 12),
            Size = new System.Drawing.Size(620, 320),
            Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
            FlowDirection = FlowDirection.TopDown,
            AutoScroll = true
        };

        _okButton = new Button
        {
            Text = "OK",
            Location = new System.Drawing.Point(470, 340),
            Size = new System.Drawing.Size(75, 23),
            Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
            DialogResult = DialogResult.OK
        };

        _cancelButton = new Button
        {
            Text = "Cancel",
            Location = new System.Drawing.Point(550, 340),
            Size = new System.Drawing.Size(75, 23),
            Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
            DialogResult = DialogResult.Cancel
        };

        this.Controls.AddRange(new Control[] { _propertyPanel, _okButton, _cancelButton });
    }

    private void CreatePropertyControls()
    {
        if (_itemType.IsValueType || _itemType == typeof(string))
        {
            // For simple types, create a single control
            CreateSimpleValueControl();
        }
        else
        {
            // For complex types, create controls for each property
            CreateComplexObjectControls();
        }
    }

    private void CreateSimpleValueControl()
    {
        var dummyProperty = new SimplePropertyInfo(_itemType, "Value");
        var control = _controlFactory.CreateControl("Value", "Value", dummyProperty, _workingValue, 
            newValue => _workingValue = newValue, _parentOptionsWindow);
        
        _propertyPanel.Controls.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.Controls.Add(control);
        }
    }

    public object GetEditedValue()
    {
        return _workingValue;
    }

    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;
            }
        }
    }
}