using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using Microsoft.UI.Xaml.Media;
using Sonex.Client.Views;
using System;
using System.Globalization;
using System.Reflection;

namespace Sonex.Client.Controls;

public delegate void TabViewItemSelectedEventHandler(object sender, TabViewItem item);

[ContentProperty(Name = nameof(View))]
public sealed class TabViewItem : SelectorBarItem
{
    private const string SelectorBarItemPaddingResourceKey = "SelectorBarItemPadding";

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.Register(
            nameof(View),
            typeof(IView),
            typeof(TabViewItem),
            new PropertyMetadata(null, OnViewChanged));

    public static readonly DependencyProperty KeyPathProperty =
        DependencyProperty.Register(
            nameof(KeyPath),
            typeof(string),
            typeof(TabViewItem),
            new PropertyMetadata(string.Empty));

    public static readonly DependencyProperty ItemTypeProperty =
        DependencyProperty.Register(
            nameof(ItemType),
            typeof(Type),
            typeof(TabViewItem),
            new PropertyMetadata(null));

    public TabViewItem()
    {
        ApplyTabPadding(new Thickness(16, 8, 16, 6));
        Background = new SolidColorBrush(Colors.Transparent);
        HorizontalAlignment = HorizontalAlignment.Stretch;
        HorizontalContentAlignment = HorizontalAlignment.Stretch;
        VerticalContentAlignment = VerticalAlignment.Stretch;
    }

    public string Header
    {
        get => Text;
        set => Text = value ?? string.Empty;
    }

    public Thickness TabPadding
    {
        get => Padding;
        set => ApplyTabPadding(value);
    }

    public IView? View
    {
        get => (IView?)GetValue(ViewProperty);
        set => SetValue(ViewProperty, value);
    }

    public string KeyPath
    {
        get => (string)GetValue(KeyPathProperty);
        set => SetValue(KeyPathProperty, value ?? string.Empty);
    }

    public Type? ItemType
    {
        get => (Type?)GetValue(ItemTypeProperty);
        set => SetValue(ItemTypeProperty, value);
    }

    public event TabViewItemSelectedEventHandler? OnSelect;

    internal event EventHandler? ViewChanged;

    internal void Load(object? item)
    {
        if (View == null)
        {
            return;
        }

        if (item == null)
        {
            View.Clear();
            return;
        }

        var itemType = ItemType;
        if (itemType != null && !itemType.IsInstanceOfType(item))
        {
            View.Clear();
            return;
        }

        var key = ResolveKey(item);
        if (string.IsNullOrWhiteSpace(key))
        {
            View.Clear();
            return;
        }

        View.Load(key);
    }

    internal void RaiseOnSelect()
    {
        OnSelect?.Invoke(this, this);
    }

    private static void OnViewChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs _)
    {
        if (dependencyObject is TabViewItem item)
        {
            item.ViewChanged?.Invoke(item, EventArgs.Empty);
        }
    }

    private string ResolveKey(object item)
    {
        if (string.IsNullOrWhiteSpace(KeyPath))
        {
            return Convert.ToString(item, CultureInfo.CurrentCulture) ?? string.Empty;
        }

        object? value = item;
        foreach (var part in KeyPath.Split('.', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
        {
            if (value == null)
            {
                return string.Empty;
            }

            var property = value.GetType().GetProperty(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
            if (property == null)
            {
                return string.Empty;
            }

            value = property.GetValue(value);
        }

        return Convert.ToString(value, CultureInfo.CurrentCulture) ?? string.Empty;
    }

    private void ApplyTabPadding(Thickness padding)
    {
        Padding = padding;
        Resources[SelectorBarItemPaddingResourceKey] = padding;
    }
}
