using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using YMhut.Box.Core.Logging;
using YMhut.Box.Core.Plugins;
using YMhut.Box.WinUI.Services;

namespace YMhut.Box.WinUI.Views;

public sealed class PluginPage : Page
{
    private static readonly TimeSpan SnapshotLoadTimeout = TimeSpan.FromSeconds(18);
    private static readonly TimeSpan ExplicitScanTimeout = TimeSpan.FromSeconds(45);

    private readonly IPluginHostProcessService _pluginHost;
    private readonly ILogService _logService;
    private readonly Action _openDocs;
    private readonly Action<LoadedPlugin, PluginSurface> _openSurface;
    private readonly Func<PluginSnapshot, Task>? _catalogChanged;
    private readonly StackPanel _pluginGrid = new()
    {
        Spacing = 12,
        Margin = new Thickness(0, 4, 0, 20)
    };
    private readonly TextBlock _statusText = ModernUi.Text("正在加载插件...", 13, foreground: ModernUi.TextSecondary);
    private readonly TextBlock _rootText = ModernUi.Text("插件根目录：等待插件宿主启动", 14, foreground: ModernUi.TextSecondary, maxLines: 2);

    private bool _scanInProgress;

    public PluginPage(
        IPluginHostProcessService pluginHost,
        ILogService logService,
        Action openDocs,
        Action<LoadedPlugin, PluginSurface> openSurface,
        Func<PluginSnapshot, Task>? catalogChanged = null)
    {
        _pluginHost = pluginHost;
        _logService = logService;
        _openDocs = openDocs;
        _openSurface = openSurface;
        _catalogChanged = catalogChanged;
        Background = ModernUi.AppBackground;
        Content = BuildContent();
        _pluginHost.SnapshotChanged += PluginHost_SnapshotChanged;
        _pluginHost.StatusChanged += PluginHost_StatusChanged;
        Loaded += async (_, _) => await LoadAsync();
        Unloaded += (_, _) =>
        {
            _pluginHost.SnapshotChanged -= PluginHost_SnapshotChanged;
            _pluginHost.StatusChanged -= PluginHost_StatusChanged;
        };
    }

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

        var title = new StackPanel
        {
            Spacing = 4,
            Children =
            {
                ModernUi.Text("插件", 32, FontWeights.SemiBold),
                _rootText
            }
        };

        var help = new Button
        {
            Content = "?",
            Width = 34,
            Height = 34,
            Padding = new Thickness(0),
            CornerRadius = new CornerRadius(17),
            FontWeight = FontWeights.SemiBold,
            UseSystemFocusVisuals = false,
            Background = ModernUi.Brush("#00FFFFFF"),
            BorderBrush = ModernUi.Brush("#00FFFFFF")
        };
        help.Click += (_, _) => _openDocs();
        ToolTipService.SetToolTip(help, "插件说明");

        var scan = ModernUi.PillButton(AppLocalizer.T("扫描插件", "Scan plugins"), "\uE72C", async () => await ScanAsync());
        var actions = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            HorizontalAlignment = HorizontalAlignment.Right,
            VerticalAlignment = VerticalAlignment.Top,
            Children = { scan, help }
        };

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

        var body = new StackPanel { Spacing = 12 };
        body.Children.Add(_statusText);
        body.Children.Add(_pluginGrid);
        var scroll = new ScrollViewer
        {
            Content = body,
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
            HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
            Padding = new Thickness(0, 0, 8, 0)
        };
        Grid.SetRow(scroll, 1);
        root.Children.Add(scroll);
        return root;
    }

    private async Task LoadAsync()
    {
        var cached = _pluginHost.CurrentSnapshot;
        if (cached is not null)
        {
            RenderSnapshot(cached);
            _statusText.Text = "已显示上次扫描结果，正在后台刷新插件状态...";
            await NotifyCatalogChangedAsync(cached);
        }
        else
        {
            _pluginGrid.Children.Clear();
            _statusText.Text = _pluginHost.Status == PluginHostStatus.Stopped
                ? "正在启动插件宿主..."
                : "正在读取插件快照...";
        }

        PluginSnapshot snapshot;
        try
        {
            using var cts = new CancellationTokenSource(SnapshotLoadTimeout);
            snapshot = await _pluginHost.GetSnapshotAsync(cts.Token);
            await NotifyCatalogChangedAsync(snapshot);
        }
        catch (Exception exception)
        {
            var safe = AppLocalizer.SanitizeSensitiveText(exception.Message, 180);
            _statusText.Text = cached is null
                ? $"插件宿主启动或读取失败：{safe}"
                : $"插件宿主暂时不可用，已保留上次扫描结果：{safe}";
            if (cached is null)
            {
                _pluginGrid.Children.Add(BuildRetryCard());
            }

            return;
        }

        RenderSnapshot(snapshot);
    }

    private async Task ScanAsync()
    {
        if (_scanInProgress)
        {
            return;
        }

        _scanInProgress = true;
        var previous = _pluginHost.CurrentSnapshot;
        if (previous is null)
        {
            _pluginGrid.Children.Clear();
        }

        _statusText.Text = AppLocalizer.T("正在扫描插件目录...", "Scanning plugin directory...");
        PluginSnapshot snapshot;
        try
        {
            _pluginHost.ResetFailedState();
            using var cts = new CancellationTokenSource(ExplicitScanTimeout);
            snapshot = await _pluginHost.ReloadAsync(cts.Token);
            await NotifyCatalogChangedAsync(snapshot);
        }
        catch (Exception exception)
        {
            var safe = AppLocalizer.SanitizeSensitiveText(exception.Message, 180);
            _statusText.Text = previous is null
                ? AppLocalizer.T($"插件扫描失败：{safe}", $"Plugin scan failed: {safe}")
                : AppLocalizer.T($"插件扫描失败，已保留上次结果：{safe}", $"Plugin scan failed; keeping the previous result: {safe}");
            if (previous is null)
            {
                _pluginGrid.Children.Add(BuildRetryCard());
            }

            await _logService.WriteAsync("Error", "plugin", "Plugin scan failed", safe);
            return;
        }
        finally
        {
            _scanInProgress = false;
        }

        RenderSnapshot(snapshot);
    }

    private Task NotifyCatalogChangedAsync(PluginSnapshot snapshot)
    {
        return _catalogChanged?.Invoke(snapshot) ?? Task.CompletedTask;
    }

    private void RenderSnapshot(PluginSnapshot snapshot)
    {
        _pluginGrid.Children.Clear();
        _rootText.Text = $"本地插件目录：{snapshot.PluginsRoot}";
        var plugins = snapshot.Plugins.Select(plugin => plugin.ToLoadedPlugin()).ToArray();
        _statusText.Text = plugins.Length == 0
            ? "还没有安装本地插件。创建插件目录并放入 ymhut.plugin.json 后点击刷新。"
            : $"已扫描 {plugins.Length} 个插件 · 插件宿主运行中 · {snapshot.LoadedAt:HH:mm:ss}";

        foreach (var plugin in plugins)
        {
            _pluginGrid.Children.Add(BuildPluginCard(plugin));
        }
    }

    private Border BuildRetryCard()
    {
        var retry = ModernUi.PillButton(AppLocalizer.T("重新扫描插件", "Scan plugins again"), "\uE72C", async () => await ScanAsync(), primary: true);
        return ModernUi.Card(new StackPanel
        {
            Spacing = 12,
            Children =
            {
                ModernUi.Text("插件宿主暂不可用", 20, FontWeights.SemiBold, ModernUi.Danger),
                ModernUi.Text("主程序仍可继续使用。请检查插件目录、宿主进程文件或稍后重试。", 13, foreground: ModernUi.TextSecondary),
                retry
            }
        }, new Thickness(16), radius: 8);
    }

    private void PluginHost_SnapshotChanged(object? sender, PluginSnapshot snapshot)
    {
        DispatcherQueue.TryEnqueue(() => RenderSnapshot(snapshot));
    }

    private void PluginHost_StatusChanged(object? sender, PluginHostStatus status)
    {
        DispatcherQueue.TryEnqueue(() =>
        {
            if (status == PluginHostStatus.Starting)
            {
                _statusText.Text = "正在启动插件宿主...";
            }
            else if (status == PluginHostStatus.Failed)
            {
                _statusText.Text = _pluginHost.CurrentSnapshot is null
                    ? "插件宿主进程异常，可点击刷新重试。"
                    : "插件宿主进程异常，已保留上次扫描结果，可点击刷新重试。";
            }
        });
    }

    private Border BuildPluginCard(LoadedPlugin plugin)
    {
        var titleRow = new Grid { ColumnSpacing = 12 };
        titleRow.ColumnDefinitions.Add(new ColumnDefinition());
        titleRow.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        titleRow.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

        var title = new StackPanel
        {
            Spacing = 4,
            Children =
            {
                ModernUi.Text(plugin.Manifest.Name, 22, FontWeights.SemiBold, maxLines: 1),
                ModernUi.Text($"v{plugin.Manifest.Version} · {plugin.Manifest.Author}", 13, foreground: ModernUi.TextSecondary, maxLines: 1),
                ModernUi.Text($"包目录：{Path.GetFileName(plugin.RootPath)}", 12, foreground: ModernUi.TextSecondary, maxLines: 1)
            }
        };
        titleRow.Children.Add(title);

        var enable = new ToggleSwitch
        {
            Header = plugin.State.Enabled ? "已启用" : "停用",
            IsOn = plugin.State.Enabled,
            IsEnabled = plugin.IsValid
        };
        enable.Toggled += async (_, _) =>
        {
            var snapshot = await _pluginHost.SetPluginEnabledAsync(plugin.Manifest.Id, enable.IsOn);
            RenderSnapshot(snapshot);
            await NotifyCatalogChangedAsync(snapshot);
        };
        Grid.SetColumn(enable, 1);
        titleRow.Children.Add(enable);

        var settings = RoundIconButton("\uE713", "插件设置", async () => await ShowPluginSettingsDialogAsync(plugin));
        settings.IsEnabled = plugin.IsValid;
        Grid.SetColumn(settings, 2);
        titleRow.Children.Add(settings);

        var panel = new StackPanel { Spacing = 14, Children = { titleRow } };
        var badges = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8 };
        badges.Children.Add(ModernUi.SmallBadge(plugin.IsValid ? "校验通过" : "校验失败", plugin.IsValid ? ModernUi.Success : ModernUi.Danger, ModernUi.SurfaceAlt));
        badges.Children.Add(ModernUi.SmallBadge(plugin.State.Enabled ? "启用" : "停用", ModernUi.TextSecondary, ModernUi.SurfaceAlt));
        badges.Children.Add(ModernUi.SmallBadge($"已授权 {GrantedPermissionCount(plugin)}/{DeclaredPermissionCount(plugin)}", ModernUi.TextSecondary, ModernUi.SurfaceAlt));
        badges.Children.Add(ModernUi.SmallBadge($"已挂载 {MountedSurfaceCount(plugin)}/{plugin.Manifest.Surfaces.Count}", ModernUi.TextSecondary, ModernUi.SurfaceAlt));
        panel.Children.Add(badges);
        panel.Children.Add(ModernUi.Text(plugin.Manifest.Description, 13, foreground: ModernUi.TextSecondary, maxLines: 2));
        panel.Children.Add(BuildStateSummary(plugin));

        if (plugin.Errors.Count > 0)
        {
            panel.Children.Add(ModernUi.Card(new TextBlock
            {
                Text = string.Join(Environment.NewLine, plugin.Errors),
                TextWrapping = TextWrapping.Wrap,
                Foreground = ModernUi.Danger,
                IsTextSelectionEnabled = true
            }, new Thickness(12), radius: 8, background: ModernUi.SurfaceAlt));
        }

        panel.Children.Add(BuildSurfaceLaunchPanel(plugin));
        var card = ModernUi.Card(panel, new Thickness(16), radius: 8);
        card.HorizontalAlignment = HorizontalAlignment.Stretch;
        return card;
    }

    private async Task ShowPluginSettingsDialogAsync(LoadedPlugin plugin)
    {
        var content = new StackPanel
        {
            Spacing = 14,
            MinWidth = 520,
            MaxWidth = 720
        };
        content.Children.Add(BuildStateSummary(plugin));
        content.Children.Add(BuildPermissionPanel(plugin));
        content.Children.Add(BuildSurfacePanel(plugin));
        content.Children.Add(await BuildLogPanelAsync(plugin));

        var scroll = new ScrollViewer
        {
            Content = content,
            MaxHeight = 620,
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
            HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled
        };

        var dialog = new ContentDialog
        {
            Title = $"{plugin.Manifest.Name} 设置",
            Content = scroll,
            CloseButtonText = "完成",
            DefaultButton = ContentDialogButton.Close,
            XamlRoot = XamlRoot
        };
        await dialog.ShowAsync();
    }

    private static Button RoundIconButton(string glyph, string tooltip, Func<Task>? click = null)
    {
        var button = new Button
        {
            Width = 34,
            Height = 34,
            Padding = new Thickness(0),
            CornerRadius = new CornerRadius(17),
            UseSystemFocusVisuals = false,
            Background = ModernUi.Brush("#00FFFFFF"),
            BorderBrush = ModernUi.Brush("#00FFFFFF"),
            Content = new FontIcon
            {
                Glyph = glyph,
                FontSize = 15,
                Foreground = ModernUi.TextSecondary
            }
        };
        ToolTipService.SetToolTip(button, tooltip);
        if (click is not null)
        {
            button.Click += async (_, _) => await click();
        }

        return button;
    }

    private UIElement BuildPermissionPanel(LoadedPlugin plugin)
    {
        var panel = new VariableSizedWrapGrid
        {
            Orientation = Orientation.Horizontal,
            ItemWidth = 154,
            ItemHeight = 36,
            HorizontalChildrenAlignment = HorizontalAlignment.Left
        };
        if (plugin.Manifest.Permissions.Count == 0)
        {
            return Section("权限授权", ModernUi.Text("未声明需要授权的 Bridge 权限。", 13, foreground: ModernUi.TextSecondary));
        }

        foreach (var permission in plugin.Manifest.Permissions.Distinct())
        {
            var check = new CheckBox
            {
                Content = permission.ToString(),
                IsChecked = plugin.State.GrantedPermissions.Contains(permission),
                IsEnabled = plugin.IsValid
            };
            check.Checked += async (_, _) =>
            {
                var snapshot = await _pluginHost.SetPermissionAsync(plugin.Manifest.Id, permission, true);
                RenderSnapshot(snapshot);
                await NotifyCatalogChangedAsync(snapshot);
            };
            check.Unchecked += async (_, _) =>
            {
                var snapshot = await _pluginHost.SetPermissionAsync(plugin.Manifest.Id, permission, false);
                RenderSnapshot(snapshot);
                await NotifyCatalogChangedAsync(snapshot);
            };
            panel.Children.Add(check);
        }

        return Section("权限授权", panel);
    }

    private UIElement BuildSurfaceLaunchPanel(LoadedPlugin plugin)
    {
        var toolboxSurfaces = plugin.Manifest.Surfaces
            .Where(surface => surface.Kind == PluginSurfaceKind.ToolboxTool)
            .ToArray();
        if (toolboxSurfaces.Length == 0)
        {
            return ModernUi.Card(
                ModernUi.Text("此插件暂未声明工具箱入口，可在设置中查看挂载项。", 13, foreground: ModernUi.TextSecondary),
                new Thickness(10),
                radius: 8,
                background: ModernUi.SurfaceAlt);
        }

        var stack = new StackPanel { Spacing = 8 };
        foreach (var surface in toolboxSurfaces)
        {
            var mounted = IsSurfaceMounted(plugin, surface);
            var row = new Grid { ColumnSpacing = 10 };
            row.ColumnDefinitions.Add(new ColumnDefinition());
            row.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

            var label = new StackPanel
            {
                Spacing = 2,
                Children =
                {
                    ModernUi.Text(surface.Name, 15, FontWeights.SemiBold, maxLines: 1),
                    ModernUi.Text(mounted ? surface.Description : "此工具未挂载，可在插件设置中开启。", 12, foreground: ModernUi.TextSecondary, maxLines: 2)
                }
            };
            row.Children.Add(label);

            var open = ModernUi.PillButton("打开工具", "\uE8A7", () => _openSurface(plugin, surface));
            open.IsEnabled = plugin.IsValid && plugin.State.Enabled && mounted;
            Grid.SetColumn(open, 1);
            row.Children.Add(open);
            stack.Children.Add(ModernUi.Card(row, new Thickness(10), radius: 8, background: ModernUi.SurfaceAlt));
        }

        return Section("工具入口", stack);
    }

    private UIElement BuildSurfacePanel(LoadedPlugin plugin)
    {
        var stack = new StackPanel { Spacing = 8 };
        if (plugin.Manifest.Surfaces.Count == 0)
        {
            stack.Children.Add(ModernUi.Text("未声明工具箱或独立页面挂载项。", 13, foreground: ModernUi.TextSecondary));
        }

        foreach (var surface in plugin.Manifest.Surfaces)
        {
            var row = new Grid { ColumnSpacing = 10 };
            row.ColumnDefinitions.Add(new ColumnDefinition());
            row.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
            row.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

            var label = new StackPanel
            {
                Spacing = 2,
                Children =
                {
                    ModernUi.Text($"{surface.Name} · {surface.Kind}", 15, FontWeights.SemiBold),
                    ModernUi.Text(surface.Description, 12, foreground: ModernUi.TextSecondary, maxLines: 2)
                }
            };
            row.Children.Add(label);

            var mounted = IsSurfaceMounted(plugin, surface);
            var toggle = new ToggleSwitch
            {
                Header = mounted ? "已挂载" : "未挂载",
                IsOn = mounted,
                IsEnabled = plugin.IsValid
            };
            toggle.Toggled += async (_, _) =>
            {
                var snapshot = await _pluginHost.SetSurfaceMountedAsync(plugin.Manifest.Id, surface.Id, toggle.IsOn);
                RenderSnapshot(snapshot);
                await NotifyCatalogChangedAsync(snapshot);
            };
            Grid.SetColumn(toggle, 1);
            row.Children.Add(toggle);

            var open = ModernUi.PillButton(surface.Kind == PluginSurfaceKind.ToolboxTool ? "打开工具" : "打开页面", "\uE8A7", () => _openSurface(plugin, surface));
            open.IsEnabled = plugin.IsValid && plugin.State.Enabled;
            Grid.SetColumn(open, 2);
            row.Children.Add(open);
            stack.Children.Add(ModernUi.Card(row, new Thickness(10), radius: 8, background: ModernUi.SurfaceAlt));
        }

        return Section("挂载项", stack);
    }

    private async Task<UIElement> BuildLogPanelAsync(LoadedPlugin plugin)
    {
        var entries = await _logService.ReadAsync(category: $"plugin:{plugin.Manifest.Id}", take: 5);
        var stack = new StackPanel { Spacing = 6 };
        if (entries.Count == 0)
        {
            stack.Children.Add(ModernUi.Text("暂无本插件日志", 13, foreground: ModernUi.TextSecondary));
        }
        else
        {
            foreach (var entry in entries)
            {
                stack.Children.Add(ModernUi.Text($"{entry.Timestamp:MM-dd HH:mm:ss} [{entry.Level}] {entry.Message}", 13, foreground: ModernUi.TextSecondary, maxLines: 2));
            }
        }

        return Section("最近日志", stack);
    }

    private static UIElement BuildStateSummary(LoadedPlugin plugin)
    {
        var lastRun = plugin.State.LastRunAt is null
            ? "尚未运行"
            : plugin.State.LastRunAt.Value.LocalDateTime.ToString("yyyy-MM-dd HH:mm");

        var grid = new Grid { ColumnSpacing = 10, RowSpacing = 8 };
        grid.ColumnDefinitions.Add(new ColumnDefinition());
        grid.ColumnDefinitions.Add(new ColumnDefinition());
        grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

        AddSummaryCell(grid, "插件 ID", plugin.Manifest.Id, 0, 0);
        AddSummaryCell(grid, "已授权", $"{GrantedPermissionCount(plugin)}/{DeclaredPermissionCount(plugin)}", 1, 0);
        AddSummaryCell(grid, "已挂载", $"{MountedSurfaceCount(plugin)}/{plugin.Manifest.Surfaces.Count}", 0, 1);
        AddSummaryCell(grid, "最近运行", lastRun, 1, 1);
        return ModernUi.Card(grid, new Thickness(10), radius: 8, background: ModernUi.SurfaceAlt);
    }

    private static int DeclaredPermissionCount(LoadedPlugin plugin)
    {
        return plugin.Manifest.Permissions.Distinct().Count();
    }

    private static int GrantedPermissionCount(LoadedPlugin plugin)
    {
        return plugin.Manifest.Permissions
            .Distinct()
            .Count(permission => plugin.State.GrantedPermissions.Contains(permission));
    }

    private static int MountedSurfaceCount(LoadedPlugin plugin)
    {
        return plugin.Manifest.Surfaces.Count(surface => IsSurfaceMounted(plugin, surface));
    }

    private static bool IsSurfaceMounted(LoadedPlugin plugin, PluginSurface surface)
    {
        return plugin.State.MountedSurfaceIds.Count == 0 || plugin.State.MountedSurfaceIds.Contains(surface.Id);
    }

    private static void AddSummaryCell(Grid grid, string title, string value, int column, int row)
    {
        var cell = new StackPanel
        {
            Spacing = 2,
            Children =
            {
                ModernUi.Text(title, 12, FontWeights.SemiBold, ModernUi.TextSecondary),
                ModernUi.Text(value, 13, FontWeights.SemiBold, maxLines: 1)
            }
        };
        Grid.SetColumn(cell, column);
        Grid.SetRow(cell, row);
        grid.Children.Add(cell);
    }

    private static UIElement Section(string title, UIElement content)
    {
        return new StackPanel
        {
            Spacing = 8,
            Children =
            {
                ModernUi.Text(title, 16, FontWeights.SemiBold),
                content
            }
        };
    }
}
