using InABox.Wpf;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using FastReport.Data;
using InABox.Core;

namespace InABox.Wpf
{

    public class DictionaryRadioItem(DictionaryRadioList parent) : DependencyObject
    {

        public DictionaryRadioList Parent => parent;

        private static readonly DependencyProperty CheckedProperty = DependencyProperty.Register(
            nameof(Checked), 
            typeof(bool), 
            typeof(DictionaryRadioItem),
            new FrameworkPropertyMetadata(
                false, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                propertyChangedCallback: CheckedChanged
            )
        );

        private static bool _isChanging = false;
        
        private static void CheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is not DictionaryRadioItem item || e.NewValue is not bool isChecked || _isChanging)
                return;
            _isChanging = true;
            item.Parent.Selected = isChecked ? item : null;
            _isChanging = false;
        }

        public bool Checked
        {
            get => (bool)GetValue(CheckedProperty);
            set => SetValue(CheckedProperty, value);
        } 
        
        private static readonly DependencyProperty KeyProperty = DependencyProperty.Register(
            nameof(Key), 
            typeof(object), 
            typeof(DictionaryRadioItem)
        );

        public object Key
        {
            get => GetValue(KeyProperty);
            set => SetValue(KeyProperty, value);
        } 
        
        private static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            nameof(Value), 
            typeof(string), 
            typeof(DictionaryRadioItem)
        );

        public string? Value
        {
            get => GetValue(ValueProperty) as string;
            set => SetValue(ValueProperty, value);
        } 
    }

    public class DictionaryRadioList : DependencyObject
    {
        private void Select(DictionaryRadioItem? selected)
        {
            var others = Items.Where(x => !Equals(x, selected)).ToArray();
            foreach (var item in others)
                item.Checked = false;
        }

        private static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(
            nameof(Selected), 
            typeof(DictionaryRadioItem), 
            typeof(DictionaryRadioList)
        );

        public DictionaryRadioItem? Selected
        {
            get => GetValue(SelectedProperty) as DictionaryRadioItem;
            set
            {
                SetValue(SelectedProperty, value);
                Select(Items.FirstOrDefault(x=>Equals(x,value)));
            }
        } 
        
        private static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
            nameof(Items), 
            typeof(CoreObservableCollection<DictionaryRadioItem>), 
            typeof(DictionaryRadioList)
        );

        public CoreObservableCollection<DictionaryRadioItem> Items
        {
            get => (CoreObservableCollection<DictionaryRadioItem>)GetValue(ItemsProperty);
            set => SetValue(ItemsProperty, value);
        }

        public DictionaryRadioList()
        {
            Items = new CoreObservableCollection<DictionaryRadioItem>();
        }
    }

    public class DictionaryRadioEditViewModel : DependencyObject
    {
        private static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            nameof(Title), 
            typeof(string), 
            typeof(DictionaryRadioEditViewModel)
        );

        public string? Title
        {
            get => GetValue(TitleProperty) as string;
            set => SetValue(TitleProperty, value);
        } 
        
        private static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
            nameof(Description), 
            typeof(string), 
            typeof(DictionaryRadioEditViewModel)
        );

        public string? Description
        {
            get => GetValue(DescriptionProperty) as string;
            set => SetValue(DescriptionProperty, value);
        } 
        
        private static readonly DependencyProperty ListProperty = DependencyProperty.Register(
            nameof(List), 
            typeof(DictionaryRadioList), 
            typeof(DictionaryRadioEditViewModel)
        );

        public DictionaryRadioList List
        {
            get => (DictionaryRadioList)GetValue(ListProperty);
            set => SetValue(ListProperty, value);
        } 
    }
    
    /// <summary>
    ///     Interaction logic for PrinterSelection.xaml
    /// </summary>
    public partial class DictionaryRadioEdit : ThemableWindow
    {
        
       
        public DictionaryRadioEdit(DictionaryRadioList list, string title, string? description )
        {
            InitializeComponent();
            ViewModel.Title = title;
            ViewModel.Description = description;
            ViewModel.List = list;
        }
        
        private void OK_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
            Close();
        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }

        public static bool Execute<T>(Dictionary<T, string> values, string title, string? description, ref T? result) where T : notnull
        {
            var list = new DictionaryRadioList();
            foreach (var key in values.Keys)
                list.Items.Add(new DictionaryRadioItem(list) { Key = key, Value = values[key], Checked = Equals(result,key)});

            var edit = new DictionaryRadioEdit(
                list,
                title,
                description);
            
            if (edit.ShowDialog() == true)
            {
                result = list.Selected != null ? (T)list.Selected.Key : default;
                return result is not null;
            }

            return false;
        }
        
    }
}