using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using Windows.System;
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 PluginHostPage : ToolPageBase
{
    private readonly LoadedPlugin _plugin;
    private readonly PluginSurface _surface;
    private readonly Action? _goBack;
    private readonly IPluginStateStore _stateStore = AppServices.GetRequiredService<IPluginStateStore>();
    private readonly ILogService _logService = AppServices.GetRequiredService<ILogService>();
    private readonly WebView2EnvironmentFactory _webViewEnvironmentFactory = AppServices.GetRequiredService<WebView2EnvironmentFactory>();
    private readonly IToolLinkNavigationService _linkNavigationService = AppServices.GetRequiredService<IToolLinkNavigationService>();
    private readonly WebView2 _webView = new();
    private readonly TextBox _outputBox = new()
    {
        Header = "输出",
        IsReadOnly = true,
        AcceptsReturn = true,
        MinHeight = 120,
        TextWrapping = TextWrapping.Wrap
    };
    private readonly TextBlock _statusText = ModernUi.Text("等待加载插件页面", 13, foreground: ModernUi.TextSecondary);
    private bool _loaded;

    public PluginHostPage(LoadedPlugin plugin, PluginSurface surface, Action? goBack = null)
    {
        _plugin = plugin;
        _surface = surface;
        _goBack = goBack;
        Background = ModernUi.AppBackground;
        Content = BuildContent();
        Loaded += PluginHostPage_Loaded;
    }

    private UIElement BuildContent()
    {
        var root = new Grid
        {
            Padding = new Thickness(32, 24, 32, 28),
            RowSpacing = 14
        };
        root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        root.RowDefinitions.Add(new RowDefinition());
        root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

        var back = ModernUi.IconButton("\uE72B", "返回", () => _goBack?.Invoke());
        var openExternal = ModernUi.IconButton("\uE8A7", "打开插件目录", async () =>
        {
            await Launcher.LaunchFolderPathAsync(_plugin.RootPath);
        });

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

        var header = new Grid { ColumnSpacing = 12 };
        header.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        header.ColumnDefinitions.Add(new ColumnDefinition());
        header.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        header.Children.Add(back);
        Grid.SetColumn(title, 1);
        header.Children.Add(title);
        Grid.SetColumn(openExternal, 2);
        header.Children.Add(openExternal);
        root.Children.Add(ModernUi.Card(header, new Thickness(14), radius: 8));

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

        var bottom = new StackPanel { Spacing = 8, Children = { _statusText, _outputBox } };
        Grid.SetRow(bottom, 2);
        root.Children.Add(ModernUi.Card(bottom, new Thickness(12), radius: 8));
        return root;
    }

    private async void PluginHostPage_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($"Plugins\\{_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.IsGeneralAutofillEnabled = false;
            _webView.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
            _webView.CoreWebView2.NavigationStarting += CoreWebView2_NavigationStarting;

            var bridge = new PluginBridge(_plugin, _webView);
            bridge.OutputChanged += (_, output) => _outputBox.Text = output;
            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", _surface.Id);
            _statusText.Text = "插件页面已加载";
        }
        catch (Exception exception)
        {
            var safe = AppLocalizer.SanitizeSensitiveText(exception.Message, 220);
            _statusText.Text = $"插件加载失败：{safe}";
            await _logService.WriteAsync("Error", $"plugin:{_plugin.Manifest.Id}", "Plugin host 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;
            _ = _linkNavigationService.OpenAsync(args.Uri);
            return;
        }

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