using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Interactivity;

namespace Inspectron.Settings.Avalonia.Configuration;

public partial class ListEditorDialog : Window
{
    private readonly Type _elementType;
    private readonly IList _workingList;
    private readonly DefaultControlFactory _controlFactory;
    private readonly OptionsWindow _parentOptionsWindow;
    private readonly string _name;

    public ListEditorDialog(Type elementType, IList originalList, DefaultControlFactory controlFactory, OptionsWindow parentOptionsWindow, string name)
    {
        _elementType = elementType;
        _controlFactory = controlFactory;
        _parentOptionsWindow = parentOptionsWindow;
        _name = name;

        var listType = typeof(List<>).MakeGenericType(elementType);
        _workingList = (IList)Activator.CreateInstance(listType)!;

        foreach (var item in originalList)
        {
            _workingList.Add(CloneObject(item));
        }

        InitializeComponent();
        Title = $"Edit {_name}";

        LoadListItems();

        ItemListBox.SelectionChanged += ItemListBox_SelectionChanged;
        BtnAdd.Click += BtnAdd_Click;
        BtnEdit.Click += BtnEdit_Click;
        BtnRemove.Click += BtnRemove_Click;
        BtnOK.Click += BtnOK_Click;
        BtnCancel.Click += BtnCancel_Click;
    }

    private void LoadListItems()
    {
        ItemListBox.Items.Clear();
        foreach (var item in _workingList)
        {
            ItemListBox.Items.Add(item?.ToString() ?? "(null)");
        }
    }

    private void ItemListBox_SelectionChanged(object? sender, SelectionChangedEventArgs e)
    {
        bool hasSelection = ItemListBox.SelectedIndex >= 0;
        BtnEdit.IsEnabled = hasSelection;
        BtnRemove.IsEnabled = hasSelection;
    }

    private async void BtnAdd_Click(object? sender, RoutedEventArgs e)
    {
        var defaultValue = GetDefaultValue(_elementType);
        var itemEditor = new ItemEditorDialog(_elementType, defaultValue, _controlFactory, _parentOptionsWindow);
        var result = await itemEditor.ShowDialog<object?>(this);
        if (result != null)
        {
            _workingList.Add(result);
            LoadListItems();
            ItemListBox.SelectedIndex = ItemListBox.Items.Count - 1;
        }
    }

    private async void BtnEdit_Click(object? sender, RoutedEventArgs e)
    {
        if (ItemListBox.SelectedIndex >= 0)
        {
            var selectedItem = _workingList[ItemListBox.SelectedIndex];
            var itemEditor = new ItemEditorDialog(_elementType, selectedItem, _controlFactory, _parentOptionsWindow);
            var result = await itemEditor.ShowDialog<object?>(this);
            if (result != null)
            {
                _workingList[ItemListBox.SelectedIndex] = result;
                LoadListItems();
            }
        }
    }

    private void BtnRemove_Click(object? sender, RoutedEventArgs e)
    {
        if (ItemListBox.SelectedIndex >= 0)
        {
            int selectedIndex = ItemListBox.SelectedIndex;
            _workingList.RemoveAt(selectedIndex);
            LoadListItems();

            if (ItemListBox.Items.Count > 0)
            {
                ItemListBox.SelectedIndex = Math.Min(selectedIndex, ItemListBox.Items.Count - 1);
            }
        }
    }

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

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

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

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

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