using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel;

namespace SmartAquaViewer.Helper
{
    public static class MultiSelectBehavior
    {
        public static readonly DependencyProperty SelectedItemsProperty =
            DependencyProperty.RegisterAttached(
                "SelectedItems", typeof(IList), typeof(MultiSelectBehavior),
                new PropertyMetadata(null, OnSelectedItemsChanged));

        public static void SetSelectedItems(DependencyObject element, IList? value)
            => element.SetValue(SelectedItemsProperty, value);
        public static IList? GetSelectedItems(DependencyObject element)
            => (IList?)element.GetValue(SelectedItemsProperty);

        private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is not ListBox lb) return;

            lb.SelectionChanged -= Lb_SelectionChanged;
            lb.SelectionChanged += Lb_SelectionChanged;

            if (e.NewValue is IList target)
            {
                target.Clear();
                foreach (var item in lb.SelectedItems) target.Add(item);
            }
        }

        private static void Lb_SelectionChanged(object? sender, SelectionChangedEventArgs e)
        {
            if (sender is not ListBox lb) return;

            var list = GetSelectedItems(lb);
            if (list != null)
            {
                foreach (var removed in e.RemovedItems) list.Remove(removed);
                foreach (var added in e.AddedItems) list.Add(added);
            }

            // Dictionary 동기화도 같이 수행
            var dict = GetSelectedDictionary(lb);
            if (dict != null)
            {
                string? keyPath = GetKeyPath(lb);
                string? valuePath = GetValuePath(lb);

                foreach (var removed in e.RemovedItems)
                {
                    var key = ResolvePath(removed, keyPath);
                    if (key != null && dict.Contains(key)) dict.Remove(key);
                }
                foreach (var added in e.AddedItems)
                {
                    var key = ResolvePath(added, keyPath);
                    var value = ResolvePath(added, valuePath);
                    if (key != null) dict[key] = value;
                }
            }
        }

        // ===== IDictionary 버전 =====
        public static readonly DependencyProperty SelectedDictionaryProperty =
            DependencyProperty.RegisterAttached(
                "SelectedDictionary", typeof(IDictionary), typeof(MultiSelectBehavior),
                new PropertyMetadata(null, OnSelectedDictionaryChanged));

        public static void SetSelectedDictionary(DependencyObject element, IDictionary? value)
            => element.SetValue(SelectedDictionaryProperty, value);
        public static IDictionary? GetSelectedDictionary(DependencyObject element)
            => (IDictionary?)element.GetValue(SelectedDictionaryProperty);

        // 선택된 항목에서 key/value를 뽑아낼 경로 (예: "Id", "Name", "User.Profile.Id")
        public static readonly DependencyProperty KeyPathProperty =
            DependencyProperty.RegisterAttached(
                "KeyPath", typeof(string), typeof(MultiSelectBehavior), new PropertyMetadata(null));

        public static void SetKeyPath(DependencyObject element, string? value)
            => element.SetValue(KeyPathProperty, value);
        public static string? GetKeyPath(DependencyObject element)
            => (string?)element.GetValue(KeyPathProperty);

        // 값 경로. 비우거나 "." 이면 아이템 자체를 값으로 사용
        public static readonly DependencyProperty ValuePathProperty =
            DependencyProperty.RegisterAttached(
                "ValuePath", typeof(string), typeof(MultiSelectBehavior), new PropertyMetadata("."));

        public static void SetValuePath(DependencyObject element, string? value)
            => element.SetValue(ValuePathProperty, value);
        public static string? GetValuePath(DependencyObject element)
            => (string?)element.GetValue(ValuePathProperty);

        private static void OnSelectedDictionaryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is not ListBox lb) return;

            lb.SelectionChanged -= Lb_SelectionChanged;
            lb.SelectionChanged += Lb_SelectionChanged;

            if (e.NewValue is IDictionary dict)
            {
                dict.Clear();

                string? keyPath = GetKeyPath(lb);
                string? valuePath = GetValuePath(lb);

                foreach (var item in lb.SelectedItems)
                {
                    var key = ResolvePath(item, keyPath);
                    var value = ResolvePath(item, valuePath);
                    if (key != null) dict[key] = value;
                }
            }
        }

        // ===== 유틸 =====
        private static object? ResolvePath(object? instance, string? path)
        {
            if (instance == null) return null;
            if (string.IsNullOrWhiteSpace(path) || path == ".") return instance;

            object? current = instance;
            foreach (var segment in path.Split('.'))
            {
                if (current == null) return null;

                // IDictionary인 중간 단계도 지원 (예: dict["Key"])
                if (current is IDictionary dict)
                {
                    if (dict.Contains(segment)) { current = dict[segment]; continue; }
                    return null;
                }

                var pd = TypeDescriptor.GetProperties(current)[segment];
                if (pd == null) return null;
                current = pd.GetValue(current);
            }
            return current;
        }
    }
}
