using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using Windows.Graphics;
using Windows.System;
using WinRT.Interop;
using YMhut.Box.Core.Logging;
using YMhut.Box.Core.Plugins;
using YMhut.Box.Core.Tools;
using YMhut.Box.WinUI.Services;

namespace YMhut.Box.WinUI.Views;

public sealed class PluginHostWindow : Window
{
    private readonly LoadedPlugin _plugin;
    private readonly PluginSurface _surface;
    private readonly PluginHostWindowPage _page;

    public PluginHostWindow(LoadedPlugin plugin, PluginSurface surface)
    {
        _plugin = plugin;
        _surface = surface;
        Title = $"{surface.Name} - {plugin.Manifest.Name}";
        _page = new PluginHostWindowPage(plugin, surface);
        Content = _page;
        WindowIconService.ApplyAppIcon(this);
        Closed += PluginHostWindow_Closed;
        ConfigureWindowSize();
    }

    private void PluginHostWindow_Closed(object sender, WindowEventArgs args)
    {
        _page.Dispose();
    }

    private void ConfigureWindowSize()
    {
        var hwnd = WindowNative.GetWindowHandle(this);
        var id = Win32Interop.GetWindowIdFromWindow(hwnd);
        var appWindow = AppWindow.GetFromWindowId(id);
        appWindow.Resize(new SizeInt32(1120, 760));
        appWindow.Title = $"{_surface.Name} - {_plugin.Manifest.Name}";
    }
}

internal sealed class PluginHostWindowPage : Page, IDisposable
{
    private readonly LoadedPlugin _plugin;
    private readonly PluginSurface _surface;
    private readonly IPluginStateStore _stateStore = AppServices.GetRequiredService<IPluginStateStore>();
    private readonly ILogService _logService = AppServices.GetRequiredService<ILogService>();
    private readonly WebView2EnvironmentFactory _webViewEnvironmentFactory = AppServices.GetRequiredService<WebView2EnvironmentFactory>();
    private readonly WebView2 _webView = new();
    private readonly Expander _outputExpander = new()
    {
        Header = AppLocalizer.T("输出", "Output"),
        IsExpanded = false
    };
    private readonly TextBox _outputBox = new()
    {
        IsReadOnly = true,
        AcceptsReturn = true,
        MinHeight = 92,
        MaxHeight = 180,
        TextWrapping = TextWrapping.Wrap
    };
    private readonly TextBlock _statusText = ModernUi.Text(AppLocalizer.T("等待加载插件窗口", "Waiting to load plugin window"), 13, foreground: ModernUi.TextSecondary);
    private PluginBridge? _bridge;
    private bool _loaded;
    private bool _disposed;

    public PluginHostWindowPage(LoadedPlugin plugin, PluginSurface surface)
    {
        _plugin = plugin;
        _surface = surface;
        Background = ModernUi.AppBackground;
        Content = BuildContent();
        Loaded += PluginHostWindowPage_Loaded;
        Unloaded += (_, _) => Dispose();
    }

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        _disposed = true;
        if (_webView.CoreWebView2 is not null)
        {
            _webView.CoreWebView2.NavigationStarting -= CoreWebView2_NavigationStarting;
        }

        _bridge?.Detach();
        _webView.Close();
    }

    private UIElement BuildContent()
    {
        var root = new Grid
        {
            RowSpacing = 0
        };
        root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        root.RowDefinitions.Add(new RowDefinition());
        root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

        var openFolder = ModernUi.IconButton("\uE8A7", AppLocalizer.T("打开插件目录", "Open plugin folder"), async () =>
        {
            await Launcher.LaunchFolderPathAsync(_plugin.RootPath);
        });

        var title = new StackPanel
        {
            Spacing = 2,
            Children =
            {
                ModernUi.Text(_surface.Name, 22, Microsoft.UI.Text.FontWeights.SemiBold, maxLines: 1),
                ModernUi.Text($"{_plugin.Manifest.Name} v{_plugin.Manifest.Version} · {_surface.Description}", 13, foreground: ModernUi.TextSecondary, maxLines: 1)
            }
        };

        var header = new Grid
        {
            Padding = new Thickness(16, 12, 16, 12),
            ColumnSpacing = 12,
            Background = ModernUi.Surface
        };
        header.ColumnDefinitions.Add(new ColumnDefinition());
        header.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        header.Children.Add(title);
        Grid.SetColumn(openFolder, 1);
        header.Children.Add(openFolder);
        root.Children.Add(header);

        var browserHost = new Grid
        {
            BorderBrush = ModernUi.Stroke,
            BorderThickness = new Thickness(0, 1, 0, 1),
            Background = ModernUi.Surface
        };
        browserHost.Children.Add(_webView);
        Grid.SetRow(browserHost, 1);
        root.Children.Add(browserHost);

        var bottom = new Grid
        {
            Padding = new Thickness(16, 10, 16, 12),
            RowSpacing = 8,
            Background = ModernUi.AppBackground
        };
        bottom.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        bottom.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        bottom.Children.Add(_statusText);
        _outputExpander.Content = _outputBox;
        Grid.SetRow(_outputExpander, 1);
        bottom.Children.Add(_outputExpander);
        Grid.SetRow(bottom, 2);
        root.Children.Add(bottom);
        return root;
    }

    private async void PluginHostWindowPage_Loaded(object sender, RoutedEventArgs e)
    {
        if (_loaded)
        {
            return;
        }

        _loaded = true;
        await LoadAsync();
    }

    private async Task LoadAsync()
    {
        try
        {
            var entryPath = Path.GetFullPath(Path.Combine(_plugin.RootPath, _surface.EffectiveEntry(_plugin.Manifest.Entry)));
            if (!PluginRegistryService.IsInside(_plugin.RootPath, entryPath) || !File.Exists(entryPath))
            {
                throw new FileNotFoundException("Plugin entry was not found inside the plugin directory.", entryPath);
            }

            var environment = await _webViewEnvironmentFactory.CreateAsync($"PluginWindows\\{_plugin.Manifest.Id}\\{_surface.Id}");
            var options = environment.CreateCoreWebView2ControllerOptions();
            options.IsInPrivateModeEnabled = false;
            await _webView.EnsureCoreWebView2Async(environment, options);
            _webView.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true;
            _webView.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = true;
            _webView.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
            _webView.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
            _webView.CoreWebView2.NavigationStarting += CoreWebView2_NavigationStarting;

            _bridge = new PluginBridge(_plugin, _webView);
            _bridge.OutputChanged += (_, output) =>
            {
                _outputBox.Text = output;
                _outputExpander.Header = string.IsNullOrWhiteSpace(output)
                    ? AppLocalizer.T("输出", "Output")
                    : AppLocalizer.T($"输出（{output.Length} 字符）", $"Output ({output.Length} chars)");
            };
            _bridge.Attach();
            await _webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(_bridge.BootstrapScript);

            _webView.Source = new Uri(entryPath);
            await _stateStore.MarkRunAsync(_plugin.Manifest.Id);
            await _logService.WriteAsync("Information", $"plugin:{_plugin.Manifest.Id}", "Plugin surface opened in window", _surface.Id);
            _statusText.Text = AppLocalizer.T("插件窗口已加载", "Plugin window loaded");
        }
        catch (Exception exception)
        {
            var safe = AppLocalizer.SanitizeSensitiveText(exception.Message, 220);
            _statusText.Text = AppLocalizer.T($"插件加载失败：{safe}", $"Plugin load failed: {safe}");
            await _logService.WriteAsync("Error", $"plugin:{_plugin.Manifest.Id}", "Plugin window failed", safe);
        }
    }

    private void CoreWebView2_NavigationStarting(CoreWebView2 sender, CoreWebView2NavigationStartingEventArgs args)
    {
        if (!Uri.TryCreate(args.Uri, UriKind.Absolute, out var uri) || !uri.IsFile)
        {
            args.Cancel = true;
            return;
        }

        var localPath = Uri.UnescapeDataString(uri.LocalPath);
        if (!PluginRegistryService.IsInside(_plugin.RootPath, localPath))
        {
            args.Cancel = true;
        }
    }
}

internal static class PluginHostWindowManager
{
    private static readonly Dictionary<string, PluginHostWindow> Windows = new(StringComparer.OrdinalIgnoreCase);

    public static void Open(LoadedPlugin plugin, PluginSurface surface)
    {
        var key = $"{plugin.Manifest.Id}:{surface.Id}";
        if (Windows.TryGetValue(key, out var existing))
        {
            existing.Activate();
            return;
        }

        var window = new PluginHostWindow(plugin, surface);
        Windows[key] = window;
        window.Closed += (_, _) => Windows.Remove(key);
        window.Activate();
    }
}
