using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Graphics;
using Windows.UI;
using WinRT.Interop;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace AmiReel;

/// <summary>
/// The application window. This hosts a Frame that displays pages. Add your
/// UI and logic to MainPage.xaml / MainPage.xaml.cs instead of here so you
/// can use Page features such as navigation events and the Loaded lifecycle.
/// </summary>
public sealed partial class MainWindow : Window
{
    private bool _exitConfirmed;

    public MainWindow()
    {
        InitializeComponent();
        App.MainWindowInstance = this;

        ExtendsContentIntoTitleBar = true;
        SetTitleBar(AppTitleBar);

        SetWindowIcon();
        SetDefaultSizeAndPosition();
        LoadTitleBarIcon();

        // Navigate the root frame to the main page on startup.
        RootFrame.Navigate(typeof(MainPage));

        AppWindow.Closing += AppWindow_Closing;
    }

    /// <summary>
    /// Sets the window's taskbar/Alt+Tab icon. <see cref="AppWindow.SetIcon(string)"/> requires an
    /// actual .ico file path (an .exe path is silently ignored), so the embedded .ico is extracted
    /// once to a stable file under %LOCALAPPDATA% and that path is used instead.
    /// </summary>
    private void SetWindowIcon()
    {
        try
        {
            string iconPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "AmiReel", "app-icon.ico");

            if (!File.Exists(iconPath))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(iconPath)!);
                Assembly assembly = Assembly.GetExecutingAssembly();
                using Stream? resource = assembly.GetManifestResourceStream("AmiReel.Assets.AppIcon.ico");
                if (resource is null) return;

                using FileStream file = File.Create(iconPath);
                resource.CopyTo(file);
            }

            AppWindow.SetIcon(iconPath);
        }
        catch
        {
            // Non-critical: the window simply keeps whatever default icon Windows assigned.
        }
    }

    /// <summary>
    /// Loads the title bar icon from an embedded resource instead of an "ms-appx:///Assets/..."
    /// URI. A single-file self-contained publish bundles Content/Assets items into the exe in a
    /// way the ms-appx resource pipeline can no longer resolve at runtime, leaving the title bar
    /// blank; a plain embedded resource stream works the same in every publish mode.
    /// </summary>
    private async void LoadTitleBarIcon()
    {
        try
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            using Stream? stream = assembly.GetManifestResourceStream("AmiReel.Assets.TitleBarIcon.png");
            if (stream is null) return;

            BitmapImage bitmap = new();
            await bitmap.SetSourceAsync(stream.AsRandomAccessStream());
            TitleBarIcon.Source = bitmap;
        }
        catch
        {
            // Non-critical: the title bar simply shows no icon if this fails.
        }
    }

    private void SetDefaultSizeAndPosition()
    {
        const int DefaultWidth = 1280;
        const int DefaultHeight = 860;
        const int MinWidth = 1100;
        const int MinHeight = 780;

        IntPtr hwnd = WindowNative.GetWindowHandle(this);
        double scale = GetDpiForWindow(hwnd) / 96.0;
        int width = (int)(DefaultWidth * scale);
        int height = (int)(DefaultHeight * scale);

        AppWindow.Resize(new SizeInt32(width, height));

        if (AppWindow.Presenter is OverlappedPresenter presenter)
        {
            presenter.PreferredMinimumWidth = (int)(MinWidth * scale);
            presenter.PreferredMinimumHeight = (int)(MinHeight * scale);
        }

        DisplayArea? displayArea = DisplayArea.GetFromWindowId(Win32Interop.GetWindowIdFromWindow(hwnd), DisplayAreaFallback.Primary);
        if (displayArea is not null)
        {
            int centerX = displayArea.WorkArea.X + (displayArea.WorkArea.Width - width) / 2;
            int centerY = displayArea.WorkArea.Y + (displayArea.WorkArea.Height - height) / 2;
            AppWindow.Move(new PointInt32(centerX, centerY));
        }
    }

    [DllImport("user32.dll")]
    private static extern int GetDpiForWindow(IntPtr hwnd);

    public void ApplyTheme(bool isDark)
    {
        if (Content is FrameworkElement root)
            root.RequestedTheme = isDark ? ElementTheme.Dark : ElementTheme.Light;

        AppWindowTitleBar titleBar = AppWindow.TitleBar;
        Color foreground = isDark ? Color.FromArgb(255, 0xF5, 0xF7, 0xFB) : Color.FromArgb(255, 0x12, 0x20, 0x33);
        Color hoverBackground = isDark ? Color.FromArgb(255, 0x2E, 0x44, 0x6C) : Color.FromArgb(255, 0xD7, 0xE4, 0xF4);

        titleBar.ButtonBackgroundColor = Colors.Transparent;
        titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
        titleBar.ButtonForegroundColor = foreground;
        titleBar.ButtonInactiveForegroundColor = foreground;
        titleBar.ButtonHoverBackgroundColor = hoverBackground;
        titleBar.ButtonHoverForegroundColor = foreground;
        titleBar.ButtonPressedBackgroundColor = hoverBackground;
        titleBar.ButtonPressedForegroundColor = foreground;
    }

    private async void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
    {
        if (_exitConfirmed) return;
        args.Cancel = true;

        FrameworkElement root = (FrameworkElement)Content;
        ContentDialog dialog = DialogHelper.CreateStyled(RootFrame.XamlRoot, root.RequestedTheme);
        dialog.Title = "Exit AmiReel?";
        dialog.Content = "Are you sure you want to close the application?";
        dialog.PrimaryButtonText = "Exit";
        dialog.CloseButtonText = "Cancel";
        dialog.DefaultButton = ContentDialogButton.Primary;

        ContentDialogResult result = await dialog.ShowAsync();
        if (result != ContentDialogResult.Primary) return;

        _exitConfirmed = true;
        Close();
    }
}
