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

namespace Inspectron.Settings.Avalonia.Configuration;

public partial class OptionsWindow : Window
{
    private readonly Dictionary<string, List<OptionSetting>> _settingsByCategory;
    private readonly IControlFactory _controlFactory;

    public OptionsWindow(IControlFactory controlFactory)
    {
        _controlFactory = controlFactory;
        _settingsByCategory = new Dictionary<string, List<OptionSetting>>();

        InitializeComponent();

        TreeViewCategories.SelectionChanged += TreeViewCategories_SelectionChanged;
        BtnOK.Click += BtnOK_Click;
        BtnCancel.Click += BtnCancel_Click;
    }

    public void LoadFromSettings(InspectronSettings inspectronSettings)
    {
        void Traverse(object nodeObj, string path)
        {
            var node = nodeObj as dynamic;
            object value = node.Value;

            if (value is string folderName)
            {
                string newPath = string.IsNullOrEmpty(path) ? folderName : $"{path}/{folderName}";
                foreach (var child in node.Children)
                    Traverse(child, newPath);
            }
            else if (value is InspectronSettings.UserSettingsInfo info)
            {
                string groupName = info.Name;
                string groupPath = string.IsNullOrEmpty(path) ? groupName : $"{path}/{groupName}";
                foreach (var pd in info.Settings)
                {
                    object owner = null;
                    string description = pd.Description;
                    if (pd is BoundPropertyDescriptor bpd)
                    {
                        owner = bpd.Owner;
                        if (string.IsNullOrEmpty(description))
                            description = bpd.DisplayName;
                    }
                    else
                    {
                        continue;
                    }
                    RegisterUserSetting(owner, bpd.PropertyInfo.Name, groupPath, description);
                }
            }
        }

        Traverse(inspectronSettings.UserSettings.Root, "");
    }

    public void RegisterUserSetting(object owner, string propertyName, string treePath, string? description = null)
    {
        var property = owner.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
        if (property == null)
            throw new ArgumentException($"Property '{propertyName}' not found on owner type.");

        if (string.IsNullOrEmpty(description))
            description = propertyName;

        var setting = new OptionSetting
        {
            Owner = owner,
            Property = property,
            Description = description,
            TreePath = treePath,
            Value = property.GetValue(owner)
        };

        if (!_settingsByCategory.TryGetValue(treePath, out var settingsList))
        {
            settingsList = new List<OptionSetting>();
            _settingsByCategory[treePath] = settingsList;
        }
        settingsList.Add(setting);

        AddTreeNodes(treePath);
    }

    private void AddTreeNodes(string treePath)
    {
        var parts = treePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

        var items = TreeViewCategories.Items;
        string currentPath = "";

        foreach (var part in parts)
        {
            currentPath = string.IsNullOrEmpty(currentPath) ? part : $"{currentPath}/{part}";

            var existing = items.OfType<TreeViewItem>().FirstOrDefault(n => (string)n.Header == part);
            if (existing == null)
            {
                existing = new TreeViewItem { Header = part, Tag = currentPath, IsExpanded = false };
                items.Add(existing);
            }
            items = existing.Items;
        }
    }

    private void TreeViewCategories_SelectionChanged(object? sender, SelectionChangedEventArgs e)
    {
        if (TreeViewCategories.SelectedItem is TreeViewItem selectedItem)
        {
            var path = selectedItem.Tag as string;
            if (path != null)
                DisplaySettings(path);
        }
    }

    private void DisplaySettings(string treePath)
    {
        SettingsPanel.Children.Clear();

        if (_settingsByCategory.TryGetValue(treePath, out var settingsList))
        {
            foreach (var setting in settingsList)
            {
                var control = _controlFactory.CreateControl(
                    setting.Property.Name,
                    setting.Description,
                    setting.Property,
                    setting.Value,
                    (newValue) =>
                    {
                        setting.Value = newValue;
                    },
                    this);

                SettingsPanel.Children.Add(control);
            }
        }
    }

    private void BtnOK_Click(object? sender, RoutedEventArgs e)
    {
        foreach (var settingsList in _settingsByCategory.Values)
        {
            foreach (var setting in settingsList)
            {
                setting.Property.SetValue(setting.Owner, setting.Value);
            }
        }

        Close(true);
    }

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