using System.Windows;
using System.Windows.Media.Animation;
using NexusShell.Services;

namespace NexusShell.Controls;

public class NexusWindow : Window
{
    public static readonly DependencyProperty AppTitleProperty =
        DependencyProperty.Register(nameof(AppTitle), typeof(string), typeof(NexusWindow),
            new PropertyMetadata(string.Empty));

    public static readonly DependencyProperty AppSubtitleProperty =
        DependencyProperty.Register(nameof(AppSubtitle), typeof(string), typeof(NexusWindow),
            new PropertyMetadata(string.Empty));

    public static readonly DependencyProperty IconDataProperty =
        DependencyProperty.Register(nameof(IconData), typeof(string), typeof(NexusWindow),
            new PropertyMetadata(string.Empty));

    public static readonly DependencyProperty MainContentProperty =
        DependencyProperty.Register(nameof(MainContent), typeof(object), typeof(NexusWindow),
            new PropertyMetadata(null));

    public static readonly DependencyProperty SideNavContentProperty =
        DependencyProperty.Register(nameof(SideNavContent), typeof(object), typeof(NexusWindow),
            new PropertyMetadata(null));

    public static readonly DependencyProperty RightPanelContentProperty =
        DependencyProperty.Register(nameof(RightPanelContent), typeof(object), typeof(NexusWindow),
            new PropertyMetadata(null));

    public static readonly DependencyProperty FooterContentProperty =
        DependencyProperty.Register(nameof(FooterContent), typeof(object), typeof(NexusWindow),
            new PropertyMetadata(null));

    public static readonly DependencyProperty ShowSideNavProperty =
        DependencyProperty.Register(nameof(ShowSideNav), typeof(bool), typeof(NexusWindow),
            new PropertyMetadata(false));

    public static readonly DependencyProperty ShowRightPanelProperty =
        DependencyProperty.Register(nameof(ShowRightPanel), typeof(bool), typeof(NexusWindow),
            new PropertyMetadata(false));

    public static readonly DependencyProperty ShowAmbientGlowProperty =
        DependencyProperty.Register(nameof(ShowAmbientGlow), typeof(bool), typeof(NexusWindow),
            new PropertyMetadata(true));

    public static readonly DependencyProperty AnimateOnLoadProperty =
        DependencyProperty.Register(nameof(AnimateOnLoad), typeof(bool), typeof(NexusWindow),
            new PropertyMetadata(true));

    public static readonly DependencyProperty ShellCornerRadiusProperty =
        DependencyProperty.Register(nameof(ShellCornerRadius), typeof(double), typeof(NexusWindow),
            new PropertyMetadata(22d));

    public static readonly DependencyProperty ShowChromeButtonsProperty =
        DependencyProperty.Register(nameof(ShowChromeButtons), typeof(bool), typeof(NexusWindow),
            new PropertyMetadata(true));

    static NexusWindow()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(NexusWindow),
            new FrameworkPropertyMetadata(typeof(NexusWindow)));
    }

    public NexusWindow()
    {
        ApplyNexusChromeStyle();
        Loaded += OnLoaded;
    }

    protected override void OnInitialized(EventArgs e)
    {
        ApplyNexusChromeStyle();
        base.OnInitialized(e);
    }

    public string AppTitle
    {
        get => (string)GetValue(AppTitleProperty);
        set => SetValue(AppTitleProperty, value);
    }

    public string AppSubtitle
    {
        get => (string)GetValue(AppSubtitleProperty);
        set => SetValue(AppSubtitleProperty, value);
    }

    public string IconData
    {
        get => (string)GetValue(IconDataProperty);
        set => SetValue(IconDataProperty, value);
    }

    public object? MainContent
    {
        get => GetValue(MainContentProperty);
        set => SetValue(MainContentProperty, value);
    }

    public object? SideNavContent
    {
        get => GetValue(SideNavContentProperty);
        set => SetValue(SideNavContentProperty, value);
    }

    public object? RightPanelContent
    {
        get => GetValue(RightPanelContentProperty);
        set => SetValue(RightPanelContentProperty, value);
    }

    public object? FooterContent
    {
        get => GetValue(FooterContentProperty);
        set => SetValue(FooterContentProperty, value);
    }

    public bool ShowSideNav
    {
        get => (bool)GetValue(ShowSideNavProperty);
        set => SetValue(ShowSideNavProperty, value);
    }

    public bool ShowRightPanel
    {
        get => (bool)GetValue(ShowRightPanelProperty);
        set => SetValue(ShowRightPanelProperty, value);
    }

    public bool ShowAmbientGlow
    {
        get => (bool)GetValue(ShowAmbientGlowProperty);
        set => SetValue(ShowAmbientGlowProperty, value);
    }

    public bool AnimateOnLoad
    {
        get => (bool)GetValue(AnimateOnLoadProperty);
        set => SetValue(AnimateOnLoadProperty, value);
    }

    public double ShellCornerRadius
    {
        get => (double)GetValue(ShellCornerRadiusProperty);
        set => SetValue(ShellCornerRadiusProperty, value);
    }

    public bool ShowChromeButtons
    {
        get => (bool)GetValue(ShowChromeButtonsProperty);
        set => SetValue(ShowChromeButtonsProperty, value);
    }

    private void ApplyNexusChromeStyle()
    {
        if (Style is not null)
        {
            return;
        }

        var style = TryFindResource("NexusAppWindowStyle") as Style
            ?? TryFindResource(typeof(NexusWindow)) as Style
            ?? Application.Current?.TryFindResource("NexusAppWindowStyle") as Style
            ?? Application.Current?.TryFindResource(typeof(NexusWindow)) as Style;

        if (style is not null)
        {
            Style = style;
        }
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        ApplyNexusChromeStyle();

        var shell = Template?.FindName("PART_ShellBorder", this) as UIElement;
        if (!AnimateOnLoad || NexusMotionPreferences.ShouldReduceMotion())
        {
            if (shell is not null)
            {
                shell.Opacity = 1;
            }

            return;
        }

        if (shell is not null)
        {
            var animation = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(200))
            {
                EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut },
            };
            shell.BeginAnimation(OpacityProperty, animation);
        }
    }
}
