using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;
using System.Globalization;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.System;
using WinRT.Interop;
using YMhut.Box.Core.Feedback;
using YMhut.Box.Core.Logging;
using YMhut.Box.Core.Settings;
using YMhut.Box.WinUI.Services;

namespace YMhut.Box.WinUI.Views;

public sealed class FeedbackPage : Page
{
    private const int MaxDailyFeedbackSubmissions = 5;

    private readonly IFeedbackPackageService _packageService = AppServices.GetRequiredService<IFeedbackPackageService>();
    private readonly IFeedbackSubmissionService _submissionService = AppServices.GetRequiredService<IFeedbackSubmissionService>();
    private readonly IFeedbackRecordStore _recordStore = AppServices.GetRequiredService<IFeedbackRecordStore>();
    private readonly ILogService _logService = AppServices.GetRequiredService<ILogService>();
    private readonly ISettingsService _settingsService = AppServices.GetRequiredService<ISettingsService>();

    private readonly TextBox _titleBox = new()
    {
        Header = AppLocalizer.T("标题", "Title"),
        PlaceholderText = AppLocalizer.T("一句话说明问题或建议", "Briefly describe the issue or suggestion")
    };
    private readonly ComboBox _typeBox = new()
    {
        Header = AppLocalizer.T("类型", "Type"),
        MinWidth = 180
    };
    private readonly ComboBox _severityBox = new()
    {
        Header = AppLocalizer.T("严重程度", "Severity"),
        MinWidth = 180
    };
    private readonly TextBox _contactBox = new()
    {
        Header = AppLocalizer.T("联系方式", "Contact"),
        PlaceholderText = AppLocalizer.T("可选：邮箱、QQ 或其他联系方式", "Optional: email, QQ, or another contact")
    };
    private readonly TextBox _bodyBox = new()
    {
        Header = AppLocalizer.T("反馈正文", "Feedback"),
        PlaceholderText = AppLocalizer.T("请描述你遇到的问题、复现步骤、期望结果或建议内容。", "Describe the issue, steps, expected result, or suggestion."),
        AcceptsReturn = true,
        TextWrapping = TextWrapping.Wrap,
        MinHeight = 180
    };
    private readonly CheckBox _logsCheck = new()
    {
        Content = AppLocalizer.T("包含今天的日志", "Include today's logs")
    };
    private readonly CheckBox _toolStatusCheck = new()
    {
        Content = AppLocalizer.T("包含工具运行状态", "Include tool status")
    };
    private readonly CheckBox _systemCheck = new()
    {
        Content = AppLocalizer.T("包含系统摘要", "Include system summary")
    };
    private readonly CheckBox _rememberDefaultsCheck = new()
    {
        Content = AppLocalizer.T("记住本次联系方式和默认选项", "Remember contact and defaults")
    };
    private readonly TextBox _feedbackCodeBox = new()
    {
        Header = AppLocalizer.T("反馈编号", "Feedback code"),
        IsReadOnly = true
    };
    private readonly TextBlock _statusQueryText = ModernUi.Text(
        AppLocalizer.T("提交后可用该编号查询处理状态。", "Use this code to check the feedback status after submission."),
        13,
        foreground: ModernUi.TextSecondary,
        maxLines: 6);
    private readonly TextBlock _dailyLimitText = ModernUi.Text(
        AppLocalizer.T("正在读取今日反馈额度...", "Loading today's feedback quota..."),
        13,
        foreground: ModernUi.TextSecondary,
        maxLines: 2);
    private readonly TextBlock _screenshotText = ModernUi.Text(AppLocalizer.T("未选择截图", "No screenshot selected"), 13, foreground: ModernUi.TextSecondary);
    private readonly InfoBar _statusBar = new()
    {
        IsOpen = true,
        Severity = InfoBarSeverity.Informational,
        Title = AppLocalizer.T("本地反馈包", "Local feedback package"),
        Message = AppLocalizer.T("发送前会先生成本地 zip，并加密上传；附加信息需勾选后才会包含。", "A local zip is created first and encrypted before upload. Attachments are opt-in.")
    };
    private readonly ProgressRing _progressRing = new()
    {
        Width = 22,
        Height = 22,
        Visibility = Visibility.Collapsed
    };
    private readonly TextBlock _packagePathText = ModernUi.Text(string.Empty, 13, foreground: ModernUi.TextSecondary, maxLines: 4);
    private readonly TextBlock _feedbackStateBadgeText = ModernUi.Text(AppLocalizer.T("未发送", "Not sent"), 12, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1);
    private readonly Border _feedbackStateBadge = new()
    {
        Padding = new Thickness(8, 3, 8, 4),
        CornerRadius = new CornerRadius(6),
        Background = ModernUi.SurfaceAlt
    };
    private readonly TextBlock _feedbackStateText = ModernUi.Text(AppLocalizer.T("该编号尚未生成反馈包。", "No package has been created for this code."), 14, FontWeights.SemiBold, maxLines: 2);
    private readonly TextBlock _feedbackStateMetaText = ModernUi.Text(AppLocalizer.T("生成或发送后，这里会显示最近状态。", "After creating or sending, the latest status appears here."), 12, foreground: ModernUi.TextSecondary, maxLines: 4);
    private readonly TextBlock _recordSummaryText = ModernUi.Text(AppLocalizer.T("最近 10 天的反馈会保留在当前列表，超过 10 天自动进入本地归档。", "Feedback from the last 10 days stays active; older items are archived locally."), 13, foreground: ModernUi.TextSecondary, maxLines: 3);
    private readonly TextBlock _serverStatusBadgeText = ModernUi.Text(AppLocalizer.T("未查询", "Not checked"), 12, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1);
    private readonly Border _serverStatusBadge = new()
    {
        Padding = new Thickness(8, 2, 8, 3),
        CornerRadius = new CornerRadius(6),
        Background = ModernUi.SurfaceAlt
    };
    private readonly TextBlock _serverStatusSummaryText = ModernUi.Text(AppLocalizer.T("尚未查询后台处理状态。", "The service handling status has not been checked."), 14, FontWeights.SemiBold, maxLines: 2);
    private readonly TextBlock _serverStatusDetailText = ModernUi.Text(AppLocalizer.T("提交反馈后可使用编号读取工单处理进度。", "After submission, use the code to read the ticket handling progress."), 13, foreground: ModernUi.TextSecondary, maxLines: 4);
    private readonly TextBlock _serverStatusMetaText = ModernUi.Text(AppLocalizer.T("分类、优先级、通知状态会在查询后显示。", "Category, priority, and notification status appear after checking."), 12, foreground: ModernUi.TextSecondary, maxLines: 4);
    private readonly TextBlock _publicReplyBadgeText = ModernUi.Text(AppLocalizer.T("暂无回复", "No reply"), 12, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1);
    private readonly Border _publicReplyBadge = new()
    {
        Padding = new Thickness(8, 2, 8, 3),
        CornerRadius = new CornerRadius(6),
        Background = ModernUi.SurfaceAlt
    };
    private readonly TextBlock _publicReplyText = ModernUi.Text(AppLocalizer.T("后台公开回复会单独显示在这里，不再和状态文本混在一起。", "Public replies appear here separately from status text."), 13, foreground: ModernUi.TextSecondary, maxLines: 8);
    private readonly StackPanel _activeRecordsPanel = new() { Spacing = 8 };
    private readonly StackPanel _archivedRecordsPanel = new() { Spacing = 8 };
    private readonly Button _sendButton;
    private readonly Button _packageOnlyButton;
    private readonly Button _retryButton;
    private readonly Button _openFolderButton;
    private readonly Button _copyPathButton;
    private readonly Button _copyCodeButton;
    private readonly Button _queryStatusButton;

    private Grid? _feedbackRoot;
    private Grid? _twoColumnsGrid;
    private Grid? _formHost;
    private VariableSizedWrapGrid? _codeActionsGrid;
    private VariableSizedWrapGrid? _actionsGrid;
    private string? _screenshotPath;
    private FeedbackRequest? _lastRequest;
    private FeedbackPackageResult? _lastPackage;
    private IReadOnlyList<FeedbackRecord> _feedbackRecords = [];
    private bool _busy;

    public FeedbackPage()
    {
        Background = ModernUi.AppBackground;
        ConfigureOptions();
        _feedbackStateBadge.Child = _feedbackStateBadgeText;
        _serverStatusBadge.Child = _serverStatusBadgeText;
        _publicReplyBadge.Child = _publicReplyBadgeText;
        RefreshFeedbackCode();
        _sendButton = ModernUi.PillButton(AppLocalizer.T("发送反馈", "Send feedback"), "\uE724", async () => await SendAsync(), primary: true);
        _packageOnlyButton = ModernUi.PillButton(AppLocalizer.T("仅生成反馈包", "Create package only"), "\uE8B7", async () => await BuildPackageOnlyAsync());
        _retryButton = ModernUi.PillButton(AppLocalizer.T("重试发送", "Retry send"), "\uE72C", async () => await RetryAsync());
        _openFolderButton = ModernUi.PillButton(AppLocalizer.T("打开反馈目录", "Open folder"), "\uE838", async () => await OpenPackageFolderAsync());
        _copyPathButton = ModernUi.PillButton(AppLocalizer.T("复制包路径", "Copy package path"), "\uE8C8", CopyPackagePath);
        _copyCodeButton = ModernUi.PillButton(AppLocalizer.T("复制编号", "Copy code"), "\uE8C8", CopyFeedbackCode);
        _queryStatusButton = ModernUi.PillButton(AppLocalizer.T("查询状态", "Check status"), "\uE9D9", async () => await QueryStatusAsync());
        SetActionSlotVisible(_retryButton, false);
        SetActionSlotVisible(_openFolderButton, false);
        SetActionSlotVisible(_copyPathButton, false);
        _progressRing.Visibility = Visibility.Visible;
        _progressRing.Opacity = 0;
        Content = BuildContent();
        Loaded += FeedbackPage_Loaded;
    }

    private async void FeedbackPage_Loaded(object sender, RoutedEventArgs e)
    {
        try
        {
            var settings = await _settingsService.LoadAsync();
            ApplySettings(settings);
            await RefreshFeedbackRecordsAsync();
        }
        catch (Exception exception)
        {
            CrashLog.Write(exception);
        }
    }

    private void ConfigureOptions()
    {
        AddOption(_typeBox, AppLocalizer.T("问题", "Issue"), "issue", selected: true);
        AddOption(_typeBox, AppLocalizer.T("建议", "Suggestion"), "suggestion");
        AddOption(_typeBox, AppLocalizer.T("界面反馈", "UI feedback"), "ui");
        AddOption(_typeBox, AppLocalizer.T("其他", "Other"), "other");

        AddOption(_severityBox, AppLocalizer.T("普通", "Normal"), "normal", selected: true);
        AddOption(_severityBox, AppLocalizer.T("影响使用", "Affects usage"), "major");
        AddOption(_severityBox, AppLocalizer.T("阻塞", "Blocking"), "blocking");
    }

    private static void AddOption(ComboBox comboBox, string label, string tag, bool selected = false)
    {
        comboBox.Items.Add(new ComboBoxItem
        {
            Content = label,
            Tag = tag,
            IsSelected = selected
        });
    }

    private void RefreshFeedbackCode()
    {
        _feedbackCodeBox.Text = FeedbackCode.Create();
        UpdateCurrentFeedbackStateUi();
    }

    private UIElement BuildContent()
    {
        _feedbackRoot = new Grid
        {
            Padding = new Thickness(32, 28, 32, 32),
            RowSpacing = 16,
            Transitions = new TransitionCollection
            {
                new EntranceThemeTransition { FromVerticalOffset = 12 }
            }
        };
        var root = _feedbackRoot;
        root.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        root.RowDefinitions.Add(new RowDefinition());
        root.Children.Add(BuildHeader());
        root.SizeChanged += (_, e) => ArrangeFeedbackLayout(e.NewSize.Width, e.NewSize.Height);

        var scroller = new ScrollViewer
        {
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
            HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
            Padding = new Thickness(0, 0, 8, 0),
            HorizontalContentAlignment = HorizontalAlignment.Stretch,
            Content = BuildForm()
        };
        Grid.SetRow(scroller, 1);
        root.Children.Add(scroller);
        ArrangeFeedbackLayout(ActualWidth, ActualHeight);
        return root;
    }

    private FrameworkElement BuildHeader()
    {
        return new StackPanel
        {
            Spacing = 4,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("反馈", "Feedback"), 28, FontWeights.SemiBold),
                ModernUi.Text(AppLocalizer.T("生成本地反馈包，加密后发送给开发者；截图、日志和系统摘要都由你决定是否包含。", "Create a local feedback package, encrypt it, and send it to the developer. You choose whether screenshots, logs, and system details are included."), 14, foreground: ModernUi.TextSecondary, maxLines: 2)
            }
        };
    }

    private FrameworkElement BuildForm()
    {
        _twoColumnsGrid = new Grid { ColumnSpacing = 12, RowSpacing = 12 };
        _twoColumnsGrid.ColumnDefinitions.Add(new ColumnDefinition());
        _twoColumnsGrid.ColumnDefinitions.Add(new ColumnDefinition());
        _twoColumnsGrid.Children.Add(_typeBox);
        Grid.SetColumn(_severityBox, 1);
        _twoColumnsGrid.Children.Add(_severityBox);

        var screenshotActions = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            Children =
            {
                ModernUi.PillButton(AppLocalizer.T("选择截图", "Choose screenshot"), "\uE8E5", async () => await PickScreenshotAsync()),
                ModernUi.PillButton(AppLocalizer.T("清除截图", "Clear screenshot"), "\uE74D", ClearScreenshot)
            }
        };

        var attachmentPanel = ModernUi.Card(new StackPanel
        {
            Spacing = 12,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("可选附加信息", "Optional attachments"), 18, FontWeights.SemiBold),
                _logsCheck,
                _toolStatusCheck,
                _systemCheck,
                _rememberDefaultsCheck,
                new StackPanel
                {
                    Spacing = 8,
                    Children =
                    {
                        screenshotActions,
                        _screenshotText,
                        ModernUi.Text(AppLocalizer.T("支持 png / jpg / jpeg / webp / bmp，单张不超过 5 MB。", "Supports png / jpg / jpeg / webp / bmp, up to 5 MB."), 12, foreground: ModernUi.TextSecondary)
                    }
                }
            }
        }, new Thickness(18), radius: 8);

        _codeActionsGrid = new VariableSizedWrapGrid
        {
            Orientation = Orientation.Horizontal,
            ItemWidth = 132,
            ItemHeight = 46,
            HorizontalChildrenAlignment = HorizontalAlignment.Left,
            VerticalChildrenAlignment = VerticalAlignment.Center,
            Children =
            {
                _copyCodeButton,
                _queryStatusButton
            }
        };

        var feedbackStateRow = new Grid
        {
            ColumnSpacing = 8,
            ColumnDefinitions =
            {
                new ColumnDefinition { Width = GridLength.Auto },
                new ColumnDefinition()
            }
        };
        feedbackStateRow.Children.Add(_feedbackStateBadge);
        Grid.SetColumn(_feedbackStateText, 1);
        feedbackStateRow.Children.Add(_feedbackStateText);

        var feedbackCodePanel = ModernUi.Card(new StackPanel
        {
            Spacing = 10,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("反馈编号", "Feedback code"), 18, FontWeights.SemiBold),
                _feedbackCodeBox,
                new StackPanel
                {
                    Spacing = 6,
                    Children =
                    {
                        ModernUi.Text(AppLocalizer.T("反馈编号状态", "Feedback code status"), 13, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1),
                        feedbackStateRow,
                        _feedbackStateMetaText
                    }
                },
                _codeActionsGrid,
                _statusQueryText,
                BuildFeedbackQuerySections(),
                _dailyLimitText
            }
        }, new Thickness(18), radius: 8);

        var recordsPanel = ModernUi.Card(new StackPanel
        {
            Spacing = 12,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("本地反馈记录", "Local feedback records"), 18, FontWeights.SemiBold),
                _recordSummaryText,
                ModernUi.Text(AppLocalizer.T("最近反馈", "Recent feedback"), 13, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1),
                _activeRecordsPanel,
                ModernUi.Text(AppLocalizer.T("本地归档", "Local archive"), 13, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1),
                _archivedRecordsPanel
            }
        }, new Thickness(18), radius: 8);

        var recordsSection = new Expander
        {
            Header = AppLocalizer.T("本地反馈记录", "Local feedback records"),
            IsExpanded = false,
            HorizontalAlignment = HorizontalAlignment.Stretch,
            Content = recordsPanel
        };

        _actionsGrid = new VariableSizedWrapGrid
        {
            Orientation = Orientation.Horizontal,
            ItemWidth = 168,
            ItemHeight = 46,
            HorizontalChildrenAlignment = HorizontalAlignment.Left,
            VerticalChildrenAlignment = VerticalAlignment.Center,
            Children =
            {
                _sendButton,
                _packageOnlyButton,
                _retryButton,
                _openFolderButton,
                _copyPathButton,
                _progressRing
            }
        };

        var packagePanel = ModernUi.Card(new StackPanel
        {
            Spacing = 10,
            Children =
            {
                ModernUi.Text(AppLocalizer.T("反馈包状态", "Package status"), 18, FontWeights.SemiBold),
                _statusBar,
                _packagePathText
            }
        }, new Thickness(18), radius: 8);

        var form = new StackPanel
        {
            HorizontalAlignment = HorizontalAlignment.Stretch,
            VerticalAlignment = VerticalAlignment.Top,
            Spacing = 14,
            ChildrenTransitions = new TransitionCollection
            {
                new EntranceThemeTransition { FromVerticalOffset = 10 }
            },
            Children =
            {
                ModernUi.Card(new StackPanel
                {
                    Spacing = 12,
                    Children =
                    {
                        _titleBox,
                        _twoColumnsGrid,
                        _contactBox,
                        _bodyBox
                    }
                }, new Thickness(18), radius: 8),
                attachmentPanel,
                _actionsGrid,
                packagePanel,
                feedbackCodePanel,
                recordsSection
            }
        };

        _formHost = new Grid
        {
            HorizontalAlignment = HorizontalAlignment.Left,
            Children = { form }
        };
        return _formHost;
    }

    private FrameworkElement BuildFeedbackQuerySections()
    {
        var statusSection = new StackPanel
        {
            Spacing = 6,
            Children =
            {
                BuildQuerySectionHeader(AppLocalizer.T("处理状态", "Handling status"), _serverStatusBadge),
                _serverStatusSummaryText,
                _serverStatusDetailText,
                _serverStatusMetaText
            }
        };

        var replySection = new StackPanel
        {
            Spacing = 6,
            Children =
            {
                BuildQuerySectionHeader(AppLocalizer.T("公开回复", "Public reply"), _publicReplyBadge),
                _publicReplyText
            }
        };

        return new StackPanel
        {
            Spacing = 10,
            Children =
            {
                statusSection,
                new Border
                {
                    Height = 1,
                    Background = ModernUi.Stroke,
                    Margin = new Thickness(0, 2, 0, 2)
                },
                replySection
            }
        };
    }

    private static FrameworkElement BuildQuerySectionHeader(string title, FrameworkElement badge)
    {
        var grid = new Grid
        {
            ColumnSpacing = 8,
            ColumnDefinitions =
            {
                new ColumnDefinition(),
                new ColumnDefinition { Width = GridLength.Auto }
            }
        };

        grid.Children.Add(ModernUi.Text(title, 13, FontWeights.SemiBold, ModernUi.TextSecondary, maxLines: 1));
        Grid.SetColumn(badge, 1);
        grid.Children.Add(badge);
        return grid;
    }

    private void ArrangeFeedbackLayout(double width, double height)
    {
        width = width > 0 ? width : ActualWidth;
        height = height > 0 ? height : ActualHeight;
        if (width <= 0)
        {
            return;
        }

        var compact = width < 640;
        var medium = width < 920;
        var horizontal = compact ? 18 : medium ? 24 : 32;
        if (_feedbackRoot is not null)
        {
            _feedbackRoot.Padding = new Thickness(horizontal, compact ? 20 : 28, horizontal + 12, compact ? 22 : 32);
        }

        if (_formHost is not null)
        {
            _formHost.Width = Math.Clamp(width - horizontal * 2 - 28, 320, compact ? 720 : 1100);
        }

        if (_twoColumnsGrid is not null)
        {
            var singleColumn = width < 700;
            _twoColumnsGrid.ColumnDefinitions.Clear();
            _twoColumnsGrid.RowDefinitions.Clear();
            _twoColumnsGrid.ColumnDefinitions.Add(new ColumnDefinition());
            if (singleColumn)
            {
                _twoColumnsGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
                _twoColumnsGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
                Grid.SetColumn(_severityBox, 0);
                Grid.SetRow(_severityBox, 1);
            }
            else
            {
                _twoColumnsGrid.ColumnDefinitions.Add(new ColumnDefinition());
                Grid.SetColumn(_severityBox, 1);
                Grid.SetRow(_severityBox, 0);
            }
        }

        if (_actionsGrid is not null)
        {
            _actionsGrid.ItemWidth = compact ? Math.Max(142, width - horizontal * 2 - 44) : medium ? 152 : 168;
        }

        if (_codeActionsGrid is not null)
        {
            _codeActionsGrid.ItemWidth = compact ? Math.Max(142, width - horizontal * 2 - 44) : 132;
        }

        _bodyBox.MinHeight = Math.Clamp(height > 0 ? height * (compact ? 0.25 : 0.22) : 180, 160, 280);
    }

    private async Task RefreshFeedbackRecordsAsync()
    {
        try
        {
            _feedbackRecords = await _recordStore.ArchiveOlderThanAsync(TimeSpan.FromDays(10));
            UpdateCurrentFeedbackStateUi();
            RenderFeedbackRecords();
        }
        catch (Exception exception)
        {
            CrashLog.Write(exception);
            _recordSummaryText.Text = AppLocalizer.T("本地反馈记录读取失败，但不会影响本次反馈发送。", "Local feedback records failed to load, but this does not block sending feedback.");
        }
    }

    private void UpdateCurrentFeedbackStateUi()
    {
        var code = FeedbackCode.Normalize(_feedbackCodeBox.Text);
        var record = FeedbackCode.IsValid(code)
            ? _feedbackRecords.FirstOrDefault(item => string.Equals(item.Code, code, StringComparison.OrdinalIgnoreCase))
            : null;

        if (record is null)
        {
            _feedbackStateBadgeText.Text = AppLocalizer.T("未发送", "Not sent");
            _feedbackStateBadgeText.Foreground = ModernUi.TextSecondary;
            _feedbackStateBadge.Background = ModernUi.SurfaceAlt;
            _feedbackStateText.Text = AppLocalizer.T("该编号尚未生成反馈包。", "No package has been created for this code.");
            _feedbackStateMetaText.Text = AppLocalizer.T("生成或发送后，这里会显示最近状态；本地记录会保留最近 10 天。", "After creating or sending, the latest status appears here. Local records stay active for 10 days.");
            UpdateServiceFeedbackUi(null);
            return;
        }

        _feedbackStateBadgeText.Text = DisplayRecordStatus(record);
        _feedbackStateBadgeText.Foreground = RecordForeground(record);
        _feedbackStateBadge.Background = RecordBackground(record);
        _feedbackStateText.Text = record.LastMessage;
        _feedbackStateMetaText.Text = RecordMeta(record, includePath: true);
        UpdateServiceFeedbackUi(record);
    }

    private void UpdateServiceFeedbackUi(FeedbackRecord? record)
    {
        if (record is null)
        {
            SetServiceStatusDisplay(
                AppLocalizer.T("未查询", "Not checked"),
                ModernUi.TextSecondary,
                ModernUi.SurfaceAlt,
                AppLocalizer.T("尚未查询后台处理状态。", "The service handling status has not been checked."),
                AppLocalizer.T("提交反馈后可使用编号读取工单处理进度。", "After submission, use the code to read the ticket handling progress."),
                AppLocalizer.T("分类、优先级、通知状态会在查询后显示。", "Category, priority, and notification status appear after checking."));
            SetPublicReplyDisplay(null);
            return;
        }

        var statusLabel = string.IsNullOrWhiteSpace(record.ServiceStatus)
            ? DisplayRecordStatus(record)
            : DisplayServiceStatus(record.ServiceStatus, record.StatusLabel);
        var detail = FirstText(
            record.ServiceStatusDetail,
            record.LastMessage,
            AppLocalizer.T("暂无更多状态说明。", "No status detail yet."));

        SetServiceStatusDisplay(
            statusLabel,
            ServiceStatusForeground(record),
            ServiceStatusBackground(record),
            AppLocalizer.T($"当前状态：{statusLabel}", $"Current status: {statusLabel}"),
            detail,
            ServiceStatusMeta(record));
        SetPublicReplyDisplay(record.PublicReply);
    }

    private void SetServiceStatusDisplay(
        string badge,
        Brush foreground,
        Brush background,
        string summary,
        string detail,
        string meta)
    {
        _serverStatusBadgeText.Text = string.IsNullOrWhiteSpace(badge) ? AppLocalizer.T("未返回", "Not returned") : badge;
        _serverStatusBadgeText.Foreground = foreground;
        _serverStatusBadge.Background = background;
        _serverStatusSummaryText.Text = summary;
        _serverStatusDetailText.Text = detail;
        _serverStatusMetaText.Text = meta;
    }

    private void SetPublicReplyDisplay(string? publicReply)
    {
        if (string.IsNullOrWhiteSpace(publicReply))
        {
            _publicReplyBadgeText.Text = AppLocalizer.T("暂无回复", "No reply");
            _publicReplyBadgeText.Foreground = ModernUi.TextSecondary;
            _publicReplyBadge.Background = ModernUi.SurfaceAlt;
            _publicReplyText.Foreground = ModernUi.TextSecondary;
            _publicReplyText.Text = AppLocalizer.T("后台暂未提供公开回复；状态说明会保留在上方处理状态区域。", "No public reply has been provided yet. Status details stay in the handling status section above.");
            return;
        }

        _publicReplyBadgeText.Text = AppLocalizer.T("已回复", "Replied");
        _publicReplyBadgeText.Foreground = ModernUi.Success;
        _publicReplyBadge.Background = ModernUi.SurfaceAlt;
        _publicReplyText.Foreground = ModernUi.TextPrimary;
        _publicReplyText.Text = AppLocalizer.SanitizeSensitiveText(publicReply, 800);
    }

    private void RenderFeedbackRecords()
    {
        _activeRecordsPanel.Children.Clear();
        _archivedRecordsPanel.Children.Clear();

        var active = _feedbackRecords.Where(record => !record.IsArchived).OrderByDescending(record => record.UpdatedAtUtc).Take(3).ToArray();
        var archived = _feedbackRecords.Where(record => record.IsArchived).OrderByDescending(record => record.ArchivedAtUtc ?? record.UpdatedAtUtc).Take(4).ToArray();
        var archivedCount = _feedbackRecords.Count(record => record.IsArchived);

        _recordSummaryText.Text = AppLocalizer.T(
            $"当前保留 {active.Length} 条最近反馈，已归档 {archivedCount} 条。超过 10 天的反馈会自动进入本地归档，仍可切换编号查询。",
            $"{active.Length} recent feedback records are active and {archivedCount} are archived. Items older than 10 days are archived locally and can still be selected for status checks.");

        if (active.Length == 0)
        {
            _activeRecordsPanel.Children.Add(ModernUi.Text(AppLocalizer.T("暂无最近反馈。", "No recent feedback yet."), 13, foreground: ModernUi.TextSecondary));
        }
        else
        {
            foreach (var record in active)
            {
                _activeRecordsPanel.Children.Add(BuildRecordRow(record));
            }
        }

        if (archived.Length == 0)
        {
            _archivedRecordsPanel.Children.Add(ModernUi.Text(AppLocalizer.T("暂无本地归档。", "No local archive yet."), 13, foreground: ModernUi.TextSecondary));
        }
        else
        {
            foreach (var record in archived)
            {
                _archivedRecordsPanel.Children.Add(BuildRecordRow(record));
            }
        }
    }

    private FrameworkElement BuildRecordRow(FeedbackRecord record)
    {
        var textPanel = new StackPanel
        {
            Spacing = 3,
            Children =
            {
                ModernUi.Text($"{record.Code} · {DisplayRecordStatus(record)}", 13, FontWeights.SemiBold, RecordForeground(record), maxLines: 1),
                ModernUi.Text(string.IsNullOrWhiteSpace(record.Title) ? AppLocalizer.T("未命名反馈", "Untitled feedback") : record.Title, 14, FontWeights.SemiBold, maxLines: 2),
                ModernUi.Text(RecordMeta(record, includePath: false), 12, foreground: ModernUi.TextSecondary, maxLines: 1),
                ModernUi.Text(record.LastMessage, 12, foreground: ModernUi.TextSecondary, maxLines: 1)
            }
        };

        var actions = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 6,
            HorizontalAlignment = HorizontalAlignment.Right,
            Children =
            {
                ModernUi.PillButton(AppLocalizer.T("使用", "Use"), "\uE8A7", () => UseFeedbackRecord(record))
            }
        };

        if (!string.IsNullOrWhiteSpace(record.PackagePath))
        {
            actions.Children.Add(ModernUi.PillButton(AppLocalizer.T("目录", "Folder"), "\uE838", async () => await OpenFeedbackRecordFolderAsync(record)));
        }

        var grid = new Grid
        {
            ColumnSpacing = 12,
            Padding = new Thickness(0, 8, 0, 10),
            ColumnDefinitions =
            {
                new ColumnDefinition(),
                new ColumnDefinition { Width = GridLength.Auto }
            }
        };
        grid.Children.Add(textPanel);
        Grid.SetColumn(actions, 1);
        grid.Children.Add(actions);

        return new Border
        {
            BorderBrush = ModernUi.Stroke,
            BorderThickness = new Thickness(0, 0, 0, 1),
            Child = grid
        };
    }

    private void UseFeedbackRecord(FeedbackRecord record)
    {
        _feedbackCodeBox.Text = record.Code;
        _statusQueryText.Text = AppLocalizer.T(
            $"已切换到反馈编号 {record.Code}，可继续查询处理状态。",
            $"Switched to feedback code {record.Code}. You can check its handling status.");
        UpdateCurrentFeedbackStateUi();
    }

    private async Task OpenFeedbackRecordFolderAsync(FeedbackRecord record)
    {
        var folderPath = string.IsNullOrWhiteSpace(record.PackagePath) ? null : Path.GetDirectoryName(record.PackagePath);
        if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
        {
            SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("目录不存在", "Folder missing"), AppLocalizer.T("该反馈包目录已不存在或无法访问。", "The feedback package folder no longer exists or cannot be accessed."));
            return;
        }

        var folder = await StorageFolder.GetFolderFromPathAsync(folderPath);
        await Launcher.LaunchFolderAsync(folder);
    }

    private async Task<FeedbackRecord> UpsertFeedbackRecordAsync(
        FeedbackRequest request,
        FeedbackPackageResult? package,
        FeedbackRecordState state,
        string statusLabel,
        string message,
        bool incrementFailure = false,
        DateTimeOffset? submittedAtUtc = null,
        DateTimeOffset? lastQueryAtUtc = null,
        string? serviceStatus = null,
        string? publicReply = null,
        string? serviceStatusDetail = null,
        string? serviceCategory = null,
        string? servicePriority = null,
        bool? serviceMailSent = null,
        string? serviceReceivedAt = null,
        string? serviceUpdatedAt = null)
    {
        var code = FeedbackCode.Normalize(request.FeedbackCode);
        if (!FeedbackCode.IsValid(code))
        {
            code = FeedbackCode.Normalize(_feedbackCodeBox.Text);
        }

        var existing = await _recordStore.FindAsync(code);
        var now = DateTimeOffset.UtcNow;
        var createdAt = existing?.CreatedAtUtc ?? package?.CreatedAt.ToUniversalTime() ?? now;
        var title = string.IsNullOrWhiteSpace(request.Title)
            ? existing?.Title ?? AppLocalizer.T("未命名反馈", "Untitled feedback")
            : request.Title.Trim();

        var record = new FeedbackRecord(
            code,
            AppLocalizer.SanitizeSensitiveText(title, 160),
            string.IsNullOrWhiteSpace(request.Type) ? existing?.Type ?? "issue" : request.Type,
            string.IsNullOrWhiteSpace(request.Severity) ? existing?.Severity ?? "normal" : request.Severity,
            createdAt,
            now,
            state,
            statusLabel,
            AppLocalizer.SanitizeSensitiveText(message, 500),
            package?.PackagePath ?? existing?.PackagePath,
            package?.PackageSha256 ?? existing?.PackageSha256,
            package?.PackageBytes ?? existing?.PackageBytes ?? 0,
            submittedAtUtc ?? existing?.SubmittedAtUtc,
            lastQueryAtUtc ?? existing?.LastQueryAtUtc,
            existing?.ArchivedAtUtc,
            existing?.IsArchived ?? false,
            Math.Max(0, existing?.FailureCount ?? 0) + (incrementFailure ? 1 : 0),
            serviceStatus ?? existing?.ServiceStatus,
            string.IsNullOrWhiteSpace(publicReply) ? existing?.PublicReply : AppLocalizer.SanitizeSensitiveText(publicReply, 500),
            string.IsNullOrWhiteSpace(serviceStatusDetail) ? existing?.ServiceStatusDetail : AppLocalizer.SanitizeSensitiveText(serviceStatusDetail, 500),
            string.IsNullOrWhiteSpace(serviceCategory) ? existing?.ServiceCategory : serviceCategory.Trim(),
            string.IsNullOrWhiteSpace(servicePriority) ? existing?.ServicePriority : servicePriority.Trim(),
            serviceMailSent ?? existing?.ServiceMailSent,
            string.IsNullOrWhiteSpace(serviceReceivedAt) ? existing?.ServiceReceivedAt : serviceReceivedAt.Trim(),
            string.IsNullOrWhiteSpace(serviceUpdatedAt) ? existing?.ServiceUpdatedAt : serviceUpdatedAt.Trim());

        var saved = await _recordStore.UpsertAsync(record);
        await RefreshFeedbackRecordsAsync();
        return saved;
    }

    private FeedbackRequest FeedbackRecordRequest(string code)
    {
        var normalized = FeedbackCode.Normalize(code);
        if (_lastRequest is not null && string.Equals(FeedbackCode.Normalize(_lastRequest.FeedbackCode), normalized, StringComparison.OrdinalIgnoreCase))
        {
            return _lastRequest;
        }

        var existing = _feedbackRecords.FirstOrDefault(record => string.Equals(record.Code, normalized, StringComparison.OrdinalIgnoreCase));
        return new FeedbackRequest(
            existing?.Title ?? string.Empty,
            existing?.Type ?? "issue",
            existing?.Severity ?? "normal",
            string.Empty,
            "status-query",
            IncludeTodayLogs: false,
            IncludeToolStatus: false,
            IncludeSystemSummary: false,
            Language: AppLocalizer.CurrentLanguage,
            FeedbackCode: normalized);
    }

    private static string DisplayServiceStatus(string? status, string? fallback = null)
    {
        var value = status?.Trim().ToLowerInvariant();
        return value switch
        {
            "new" => AppLocalizer.T("新反馈", "New"),
            "triaged" => AppLocalizer.T("已归类", "Triaged"),
            "investigating" => AppLocalizer.T("处理中", "Investigating"),
            "resolved" => AppLocalizer.T("已解决", "Resolved"),
            "archived" => AppLocalizer.T("已归档", "Archived"),
            _ => FirstText(fallback, status, AppLocalizer.T("未知状态", "Unknown status"))
        };
    }

    private static string DisplayServiceCategory(string? category)
    {
        var value = category?.Trim().ToLowerInvariant();
        return value switch
        {
            "issue" => AppLocalizer.T("问题", "Issue"),
            "suggestion" => AppLocalizer.T("建议", "Suggestion"),
            "ui" => AppLocalizer.T("界面反馈", "UI feedback"),
            "other" => AppLocalizer.T("其他", "Other"),
            _ => FirstText(category, AppLocalizer.T("未返回", "Not returned"))
        };
    }

    private static string DisplayServicePriority(string? priority)
    {
        var value = priority?.Trim().ToLowerInvariant();
        return value switch
        {
            "normal" => AppLocalizer.T("普通", "Normal"),
            "major" => AppLocalizer.T("影响使用", "Affects usage"),
            "blocking" => AppLocalizer.T("阻塞", "Blocking"),
            _ => FirstText(priority, AppLocalizer.T("未返回", "Not returned"))
        };
    }

    private static Brush ServiceStatusForeground(FeedbackRecord record)
    {
        return record.ServiceStatus?.Trim().ToLowerInvariant() switch
        {
            "new" or "triaged" or "investigating" => ModernUi.Accent,
            "resolved" => ModernUi.Success,
            "archived" => ModernUi.TextSecondary,
            _ => RecordForeground(record)
        };
    }

    private static Brush ServiceStatusBackground(FeedbackRecord record)
    {
        return record.ServiceStatus?.Trim().ToLowerInvariant() switch
        {
            "new" or "triaged" or "investigating" => ModernUi.AccentSoft,
            _ => RecordBackground(record)
        };
    }

    private static string ServiceStatusMeta(FeedbackRecord record)
    {
        var pieces = new List<string>
        {
            AppLocalizer.T($"分类：{DisplayServiceCategory(record.ServiceCategory)}", $"Category: {DisplayServiceCategory(record.ServiceCategory)}"),
            AppLocalizer.T($"优先级：{DisplayServicePriority(record.ServicePriority)}", $"Priority: {DisplayServicePriority(record.ServicePriority)}")
        };

        if (record.ServiceMailSent is not null)
        {
            pieces.Add(record.ServiceMailSent.Value
                ? AppLocalizer.T("通知：已发送", "Notification: sent")
                : AppLocalizer.T("通知：待发送", "Notification: pending"));
        }
        else
        {
            pieces.Add(AppLocalizer.T("通知：未返回", "Notification: not returned"));
        }

        if (!string.IsNullOrWhiteSpace(record.ServiceUpdatedAt))
        {
            pieces.Add(AppLocalizer.T($"更新：{record.ServiceUpdatedAt}", $"Updated: {record.ServiceUpdatedAt}"));
        }
        else if (record.LastQueryAtUtc is not null)
        {
            pieces.Add(AppLocalizer.T($"查询：{FormatLocalTime(record.LastQueryAtUtc.Value)}", $"Checked: {FormatLocalTime(record.LastQueryAtUtc.Value)}"));
        }

        return string.Join(" · ", pieces);
    }

    private static string FirstText(params string?[] values)
    {
        foreach (var value in values)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                return value.Trim();
            }
        }

        return string.Empty;
    }

    private static string DisplayRecordStatus(FeedbackRecord record)
    {
        if (record.IsArchived && record.State != FeedbackRecordState.Archived)
        {
            return $"已归档 · {record.StatusLabel}";
        }

        return string.IsNullOrWhiteSpace(record.StatusLabel) ? RecordStateLabel(record.State) : record.StatusLabel;
    }

    private static string RecordStateLabel(FeedbackRecordState state)
    {
        return state switch
        {
            FeedbackRecordState.PackageCreated => AppLocalizer.T("反馈包已生成", "Package created"),
            FeedbackRecordState.PackageFailed => AppLocalizer.T("生成失败", "Package failed"),
            FeedbackRecordState.Sending => AppLocalizer.T("发送中", "Sending"),
            FeedbackRecordState.Sent => AppLocalizer.T("发送成功", "Sent"),
            FeedbackRecordState.SendFailed => AppLocalizer.T("发送失败", "Send failed"),
            FeedbackRecordState.Querying => AppLocalizer.T("获取状态中", "Checking"),
            FeedbackRecordState.StatusUpdated => AppLocalizer.T("状态已更新", "Status updated"),
            FeedbackRecordState.QueryFailed => AppLocalizer.T("获取失败", "Query failed"),
            FeedbackRecordState.Archived => AppLocalizer.T("已归档", "Archived"),
            _ => AppLocalizer.T("未发送", "Not sent")
        };
    }

    private static Brush RecordForeground(FeedbackRecord record)
    {
        if (record.IsArchived)
        {
            return ModernUi.TextSecondary;
        }

        return record.State switch
        {
            FeedbackRecordState.Sent or FeedbackRecordState.StatusUpdated => ModernUi.Success,
            FeedbackRecordState.SendFailed or FeedbackRecordState.QueryFailed or FeedbackRecordState.PackageFailed => ModernUi.Danger,
            FeedbackRecordState.Sending or FeedbackRecordState.Querying => ModernUi.Accent,
            _ => ModernUi.TextSecondary
        };
    }

    private static Brush RecordBackground(FeedbackRecord record)
    {
        if (record.IsArchived)
        {
            return ModernUi.SurfaceAlt;
        }

        return record.State switch
        {
            FeedbackRecordState.Sending or FeedbackRecordState.Querying => ModernUi.AccentSoft,
            _ => ModernUi.SurfaceAlt
        };
    }

    private static string RecordMeta(FeedbackRecord record, bool includePath)
    {
        var updated = FormatLocalTime(record.UpdatedAtUtc);
        var created = FormatLocalTime(record.CreatedAtUtc);
        var pieces = new List<string>
        {
            AppLocalizer.T($"创建：{created}", $"Created: {created}"),
            AppLocalizer.T($"更新：{updated}", $"Updated: {updated}")
        };

        if (record.SubmittedAtUtc is not null)
        {
            pieces.Add(AppLocalizer.T($"发送：{FormatLocalTime(record.SubmittedAtUtc.Value)}", $"Sent: {FormatLocalTime(record.SubmittedAtUtc.Value)}"));
        }

        if (record.LastQueryAtUtc is not null)
        {
            pieces.Add(AppLocalizer.T($"查询：{FormatLocalTime(record.LastQueryAtUtc.Value)}", $"Checked: {FormatLocalTime(record.LastQueryAtUtc.Value)}"));
        }

        if (record.FailureCount > 0)
        {
            pieces.Add(AppLocalizer.T($"失败 {record.FailureCount} 次", $"{record.FailureCount} failures"));
        }

        if (record.IsArchived)
        {
            pieces.Add(AppLocalizer.T("本地归档", "Local archive"));
        }

        if (includePath && !string.IsNullOrWhiteSpace(record.PackagePath))
        {
            pieces.Add(AppLocalizer.T($"反馈包：{Path.GetFileName(record.PackagePath)}", $"Package: {Path.GetFileName(record.PackagePath)}"));
        }

        return string.Join(" · ", pieces);
    }

    private static string FormatLocalTime(DateTimeOffset value)
    {
        return value.ToLocalTime().ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
    }

    private async Task PickScreenshotAsync()
    {
        var picker = new FileOpenPicker();
        foreach (var extension in new[] { ".png", ".jpg", ".jpeg", ".webp", ".bmp" })
        {
            picker.FileTypeFilter.Add(extension);
        }

        if (App.CurrentWindow is not null)
        {
            InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(App.CurrentWindow));
        }

        var file = await picker.PickSingleFileAsync();
        if (file is null)
        {
            return;
        }

        var info = new FileInfo(file.Path);
        if (info.Length > FeedbackPackageService.MaxScreenshotBytes)
        {
            SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("截图过大", "Screenshot too large"), AppLocalizer.T("截图不能超过 5 MB。", "Screenshot must be 5 MB or smaller."));
            return;
        }

        _screenshotPath = info.FullName;
        _screenshotText.Text = $"{info.Name} · {info.Length / 1024d:0.#} KB";
    }

    private void ClearScreenshot()
    {
        _screenshotPath = null;
        _screenshotText.Text = AppLocalizer.T("未选择截图", "No screenshot selected");
    }

    private async Task BuildPackageOnlyAsync()
    {
        var request = CreateRequest();
        if (request is null)
        {
            return;
        }

        await SaveFeedbackDefaultsAsync(request);
        await BuildPackageAsync(request);
    }

    private async Task SendAsync()
    {
        if (!await EnsureDailyQuotaAsync())
        {
            return;
        }

        var request = CreateRequest();
        if (request is null)
        {
            return;
        }

        await SaveFeedbackDefaultsAsync(request);
        var package = await BuildPackageAsync(request);
        if (package is null)
        {
            return;
        }

        await SubmitPackageAsync(request, package);
    }

    private async Task RetryAsync()
    {
        if (_lastRequest is null || _lastPackage is null)
        {
            SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("没有可重试的反馈包", "No package to retry"), AppLocalizer.T("请先生成反馈包。", "Create a package first."));
            return;
        }

        if (!await EnsureDailyQuotaAsync())
        {
            return;
        }

        await SubmitPackageAsync(_lastRequest, _lastPackage);
    }

    private async Task<FeedbackPackageResult?> BuildPackageAsync(FeedbackRequest request)
    {
        if (_busy)
        {
            return null;
        }

        SetBusy(true);
        try
        {
            SetStatus(InfoBarSeverity.Informational, AppLocalizer.T("正在生成反馈包", "Creating package"), AppLocalizer.T("正在写入本地 zip。", "Writing local zip."));
            var package = await _packageService.BuildPackageAsync(request);
            _lastRequest = request;
            _lastPackage = package;
            _packagePathText.Text = PackageSummary(package);
            ToolTipService.SetToolTip(_packagePathText, package.PackagePath);
            SetActionSlotVisible(_openFolderButton, true);
            SetActionSlotVisible(_copyPathButton, true);
            await UpsertFeedbackRecordAsync(
                request,
                package,
                FeedbackRecordState.PackageCreated,
                AppLocalizer.T("反馈包已生成", "Package created"),
                AppLocalizer.T("本地反馈包已生成，可发送或稍后重试。", "The local feedback package is ready for sending or retrying later."));
            SetStatus(InfoBarSeverity.Success, AppLocalizer.T("反馈包已生成", "Package created"), AppLocalizer.T("本地 zip 已保留，可发送或稍后重试。", "The local zip is retained for sending or retry."));
            await _logService.WriteAsync("Information", "feedback", "反馈包已生成", package.PackagePath);
            return package;
        }
        catch (Exception exception)
        {
            var safe = AppLocalizer.SanitizeSensitiveText(exception.Message, 220);
            await UpsertFeedbackRecordAsync(
                request,
                null,
                FeedbackRecordState.PackageFailed,
                AppLocalizer.T("生成失败", "Package failed"),
                safe,
                incrementFailure: true);
            SetStatus(InfoBarSeverity.Error, AppLocalizer.T("生成反馈包失败", "Failed to create package"), safe);
            await _logService.WriteAsync("Error", "feedback", "生成反馈包失败", safe);
            return null;
        }
        finally
        {
            SetBusy(false);
        }
    }

    private async Task SubmitPackageAsync(FeedbackRequest request, FeedbackPackageResult package)
    {
        if (_busy)
        {
            return;
        }

        SetBusy(true);
        try
        {
            SetStatus(InfoBarSeverity.Informational, AppLocalizer.T("正在发送反馈", "Sending feedback"), AppLocalizer.T("正在加密反馈包并连接开发者反馈服务。", "Encrypting the feedback package and connecting to the developer feedback service."));
            await UpsertFeedbackRecordAsync(
                request,
                package,
                FeedbackRecordState.Sending,
                AppLocalizer.T("发送中", "Sending"),
                AppLocalizer.T("正在加密反馈包并连接反馈服务。", "Encrypting the feedback package and connecting to the feedback service."));
            var response = await _submissionService.SubmitAsync(request, package);
            if (response.Ok)
            {
                SetActionSlotVisible(_retryButton, false);
                var code = response.Code ?? AppLocalizer.T("未返回编号", "No code returned");
                var finalCode = FeedbackCode.Normalize(code);
                if (FeedbackCode.IsValid(code))
                {
                    var previousCode = FeedbackCode.Normalize(request.FeedbackCode);
                    if (FeedbackCode.IsValid(previousCode) && !string.Equals(previousCode, finalCode, StringComparison.OrdinalIgnoreCase))
                    {
                        await _recordStore.RemoveAsync(previousCode);
                        request = request with { FeedbackCode = finalCode };
                    }

                    _feedbackCodeBox.Text = finalCode;
                }

                await UpsertFeedbackRecordAsync(
                    request,
                    package,
                    FeedbackRecordState.Sent,
                    response.Duplicate ? AppLocalizer.T("发送成功（已存在）", "Sent (already exists)") : AppLocalizer.T("发送成功", "Sent"),
                    AppLocalizer.T($"服务端已接收，反馈编号：{code}", $"The service received it. Feedback code: {code}"),
                    submittedAtUtc: DateTimeOffset.UtcNow);
                SetStatus(InfoBarSeverity.Success, AppLocalizer.T("反馈发送成功", "Feedback sent"), AppLocalizer.T($"反馈编号：{code}", $"Feedback code: {code}"));
                _statusQueryText.Text = AppLocalizer.T($"已提交。可用编号 {code} 查询后台处理状态。", $"Submitted. Use {code} to check the handling status.");
                ToastService.Show(AppLocalizer.T($"反馈发送成功：{code}", $"Feedback sent: {code}"), ToastKind.Success);
                await _logService.WriteAsync("Information", "feedback", "反馈发送成功", code);
                if (!response.Duplicate)
                {
                    await RecordSuccessfulSubmissionAsync();
                }
            }
            else
            {
                SetActionSlotVisible(_retryButton, true);
                var error = response.ErrorCode ?? "UNKNOWN_ERROR";
                await UpsertFeedbackRecordAsync(
                    request,
                    package,
                    FeedbackRecordState.SendFailed,
                    AppLocalizer.T("发送失败", "Send failed"),
                    $"{error} · {response.Message}",
                    incrementFailure: true);
                SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("反馈发送失败", "Feedback send failed"), $"{error} · {response.Message}");
                ToastService.Show(AppLocalizer.T("反馈包已保留，可稍后重试。", "Package retained. Retry later."), ToastKind.Warning);
                await _logService.WriteAsync("Warning", "feedback", "反馈发送失败", $"{error} · {response.Message}");
            }
        }
        finally
        {
            SetBusy(false);
        }
    }

    private async Task QueryStatusAsync()
    {
        if (_busy)
        {
            return;
        }

        var code = FeedbackCode.Normalize(_feedbackCodeBox.Text);
        if (!FeedbackCode.IsValid(code))
        {
            RefreshFeedbackCode();
            code = _feedbackCodeBox.Text;
        }

        SetBusy(true);
        try
        {
            SetStatus(InfoBarSeverity.Informational, AppLocalizer.T("正在查询反馈状态", "Checking feedback status"), AppLocalizer.T($"正在查询编号：{code}", $"Checking code: {code}"));
            var statusRequest = FeedbackRecordRequest(code);
            await UpsertFeedbackRecordAsync(
                statusRequest,
                null,
                FeedbackRecordState.Querying,
                AppLocalizer.T("获取状态中", "Checking"),
                AppLocalizer.T($"正在查询反馈编号：{code}", $"Checking feedback code: {code}"),
                lastQueryAtUtc: DateTimeOffset.UtcNow);
            var response = await _submissionService.GetStatusAsync(code);
            if (response.Ok)
            {
                if (FeedbackCode.IsValid(response.Code))
                {
                    var responseCode = FeedbackCode.Normalize(response.Code);
                    _feedbackCodeBox.Text = responseCode;
                    statusRequest = statusRequest with { FeedbackCode = responseCode };
                }

                var status = DisplayServiceStatus(response.Status, response.StatusLabel);
                var statusDetail = FirstText(
                    response.StatusDetail,
                    AppLocalizer.T($"当前状态：{status}", $"Current status: {status}"));
                var publicReply = response.HasReply && !string.IsNullOrWhiteSpace(response.Reply)
                    ? response.Reply
                    : null;

                _statusQueryText.Text = AppLocalizer.T("查询成功：处理状态和公开回复已分开展示。", "Checked: handling status and public reply are shown separately.");
                await UpsertFeedbackRecordAsync(
                    statusRequest,
                    null,
                    FeedbackRecordState.StatusUpdated,
                    status,
                    statusDetail,
                    lastQueryAtUtc: DateTimeOffset.UtcNow,
                    serviceStatus: response.Status ?? status,
                    publicReply: publicReply,
                    serviceStatusDetail: response.StatusDetail,
                    serviceCategory: response.Category,
                    servicePriority: response.Priority,
                    serviceMailSent: response.MailSent,
                    serviceReceivedAt: response.ReceivedAt,
                    serviceUpdatedAt: response.UpdatedAt);
                SetStatus(
                    response.HasReply ? InfoBarSeverity.Success : InfoBarSeverity.Informational,
                    AppLocalizer.T("反馈状态已更新", "Feedback status updated"),
                    AppLocalizer.T($"当前状态：{status}", $"Current status: {status}"));
                await _logService.WriteAsync("Information", "feedback", "反馈状态查询成功", $"{code} {status}");
            }
            else
            {
                var error = response.ErrorCode ?? "UNKNOWN_ERROR";
                var message = response.Message ?? AppLocalizer.T("后台暂未返回该反馈编号。", "The service did not return this feedback code.");
                _statusQueryText.Text = AppLocalizer.T($"查询失败：{error}\n{message}", $"Query failed: {error}\n{message}");
                await UpsertFeedbackRecordAsync(
                    statusRequest,
                    null,
                    FeedbackRecordState.QueryFailed,
                    AppLocalizer.T("获取失败", "Query failed"),
                    $"{error} · {message}",
                    incrementFailure: true,
                    lastQueryAtUtc: DateTimeOffset.UtcNow);
                SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("未查询到反馈状态", "Feedback status unavailable"), $"{error} · {message}");
                await _logService.WriteAsync("Warning", "feedback", "反馈状态查询失败", $"{code} {error}");
            }
        }
        finally
        {
            SetBusy(false);
        }
    }

    private FeedbackRequest? CreateRequest()
    {
        if (string.IsNullOrWhiteSpace(_bodyBox.Text))
        {
            SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("请填写反馈正文", "Feedback body required"), AppLocalizer.T("正文为必填项。", "The body is required."));
            _bodyBox.Focus(FocusState.Programmatic);
            return null;
        }

        return new FeedbackRequest(
            _titleBox.Text.Trim(),
            SelectedTag(_typeBox, "issue"),
            SelectedTag(_severityBox, "normal"),
            _contactBox.Text.Trim(),
            _bodyBox.Text.Trim(),
            _logsCheck.IsChecked == true,
            _toolStatusCheck.IsChecked == true,
            _systemCheck.IsChecked == true,
            _screenshotPath,
            AppLocalizer.CurrentLanguage,
            FeedbackCode.Normalize(_feedbackCodeBox.Text));
    }

    private void ApplySettings(AppSettings settings)
    {
        _contactBox.Text = settings.FeedbackDefaultContact;
        _logsCheck.IsChecked = settings.FeedbackIncludeTodayLogsByDefault;
        _toolStatusCheck.IsChecked = settings.FeedbackIncludeToolStatusByDefault;
        _systemCheck.IsChecked = settings.FeedbackIncludeSystemSummaryByDefault;
        _rememberDefaultsCheck.IsChecked = settings.FeedbackRememberDefaults;
        SelectTag(_typeBox, settings.FeedbackDefaultType, "issue");
        SelectTag(_severityBox, settings.FeedbackDefaultSeverity, "normal");
        UpdateDailyLimitText(DailySubmittedCount(settings));
    }

    private async Task SaveFeedbackDefaultsAsync(FeedbackRequest request)
    {
        if (_rememberDefaultsCheck.IsChecked != true)
        {
            await _settingsService.UpdateAsync(settings => settings.FeedbackRememberDefaults = false);
            return;
        }

        await _settingsService.UpdateAsync(settings =>
        {
            settings.FeedbackRememberDefaults = true;
            settings.FeedbackDefaultContact = request.Contact;
            settings.FeedbackDefaultType = NormalizeFeedbackType(request.Type);
            settings.FeedbackDefaultSeverity = NormalizeFeedbackSeverity(request.Severity);
            settings.FeedbackIncludeTodayLogsByDefault = request.IncludeTodayLogs;
            settings.FeedbackIncludeToolStatusByDefault = request.IncludeToolStatus;
            settings.FeedbackIncludeSystemSummaryByDefault = request.IncludeSystemSummary;
        });
    }

    private static string SelectedTag(ComboBox comboBox, string fallback)
    {
        return comboBox.SelectedItem is ComboBoxItem item && item.Tag is string value
            ? value
            : fallback;
    }

    private static void SelectTag(ComboBox comboBox, string value, string fallback)
    {
        var normalized = string.IsNullOrWhiteSpace(value) ? fallback : value;
        foreach (var item in comboBox.Items.OfType<ComboBoxItem>())
        {
            if (item.Tag is string tag && string.Equals(tag, normalized, StringComparison.OrdinalIgnoreCase))
            {
                comboBox.SelectedItem = item;
                return;
            }
        }

        foreach (var item in comboBox.Items.OfType<ComboBoxItem>())
        {
            if (item.Tag is string tag && string.Equals(tag, fallback, StringComparison.OrdinalIgnoreCase))
            {
                comboBox.SelectedItem = item;
                return;
            }
        }
    }

    private static string NormalizeFeedbackType(string value)
    {
        return value.Trim().ToLowerInvariant() switch
        {
            "suggestion" => "suggestion",
            "ui" => "ui",
            "other" => "other",
            _ => "issue"
        };
    }

    private static string NormalizeFeedbackSeverity(string value)
    {
        return value.Trim().ToLowerInvariant() switch
        {
            "major" => "major",
            "blocking" => "blocking",
            _ => "normal"
        };
    }

    private void SetStatus(InfoBarSeverity severity, string title, string message)
    {
        _statusBar.Severity = severity;
        _statusBar.Title = title;
        _statusBar.Message = message;
        _statusBar.IsOpen = true;
    }

    private void SetBusy(bool busy)
    {
        _busy = busy;
        _progressRing.IsActive = busy;
        _progressRing.Opacity = busy ? 1 : 0;
        _sendButton.IsEnabled = !busy;
        _packageOnlyButton.IsEnabled = !busy;
        _retryButton.IsEnabled = !busy && DailyRemaining(_settingsService.Current) > 0;
        _copyCodeButton.IsEnabled = !busy;
        _queryStatusButton.IsEnabled = !busy;
        if (!busy)
        {
            _sendButton.IsEnabled = DailyRemaining(_settingsService.Current) > 0;
        }
    }

    private static void SetActionSlotVisible(Button button, bool visible)
    {
        button.Visibility = Visibility.Visible;
        button.Opacity = visible ? 1 : 0;
        button.IsHitTestVisible = visible;
        button.IsTabStop = visible;
        button.IsEnabled = visible;
    }

    private async Task<bool> EnsureDailyQuotaAsync()
    {
        var settings = await _settingsService.LoadAsync();
        var submitted = DailySubmittedCount(settings);
        UpdateDailyLimitText(submitted);
        if (submitted < MaxDailyFeedbackSubmissions)
        {
            return true;
        }

        var message = AppLocalizer.T("今天最多发送 5 条反馈。你仍然可以生成本地反馈包，明天再发送。", "You can send up to 5 feedback items per day. You can still create a local package and send it tomorrow.");
        SetStatus(InfoBarSeverity.Warning, AppLocalizer.T("今日反馈次数已用完", "Today's feedback quota is used"), message);
        ToastService.Show(AppLocalizer.T("今日反馈次数已用完", "Today's feedback quota is used"), ToastKind.Warning);
        _sendButton.IsEnabled = false;
        _retryButton.IsEnabled = false;
        return false;
    }

    private async Task RecordSuccessfulSubmissionAsync()
    {
        var today = DailyLimitDateKey();
        var submitted = 0;
        await _settingsService.UpdateAsync(settings =>
        {
            if (!string.Equals(settings.FeedbackDailySubmissionDate, today, StringComparison.Ordinal))
            {
                settings.FeedbackDailySubmissionDate = today;
                settings.FeedbackDailySubmissionCount = 0;
            }

            settings.FeedbackDailySubmissionCount = Math.Clamp(settings.FeedbackDailySubmissionCount + 1, 0, MaxDailyFeedbackSubmissions);
            submitted = settings.FeedbackDailySubmissionCount;
        });

        UpdateDailyLimitText(submitted);
    }

    private void UpdateDailyLimitText(int submitted)
    {
        var remaining = Math.Max(0, MaxDailyFeedbackSubmissions - submitted);
        _dailyLimitText.Text = AppLocalizer.T(
            $"今日还可发送 {remaining}/{MaxDailyFeedbackSubmissions} 条反馈。",
            $"{remaining}/{MaxDailyFeedbackSubmissions} feedback submissions remaining today.");
        _sendButton.IsEnabled = !_busy && remaining > 0;
        _retryButton.IsEnabled = !_busy && remaining > 0;
    }

    private static int DailyRemaining(AppSettings settings)
    {
        return Math.Max(0, MaxDailyFeedbackSubmissions - DailySubmittedCount(settings));
    }

    private static int DailySubmittedCount(AppSettings settings)
    {
        return string.Equals(settings.FeedbackDailySubmissionDate, DailyLimitDateKey(), StringComparison.Ordinal)
            ? Math.Clamp(settings.FeedbackDailySubmissionCount, 0, MaxDailyFeedbackSubmissions)
            : 0;
    }

    private static string DailyLimitDateKey()
    {
        return DateTimeOffset.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
    }

    private static string PackageSummary(FeedbackPackageResult package)
    {
        var fileName = Path.GetFileName(package.PackagePath);
        var hash = package.PackageSha256.Length > 12 ? package.PackageSha256[..12] : package.PackageSha256;
        return AppLocalizer.T(
            $"文件：{fileName}\n大小：{FormatBytes(package.PackageBytes)}\nSHA256：{hash}...\n完整路径可复制或打开目录查看。",
            $"File: {fileName}\nSize: {FormatBytes(package.PackageBytes)}\nSHA256: {hash}...\nCopy the full path or open the folder to view it.");
    }

    private static string FormatBytes(long bytes)
    {
        var units = new[] { "B", "KB", "MB", "GB" };
        var value = (double)Math.Max(0, bytes);
        var index = 0;
        while (value >= 1024 && index < units.Length - 1)
        {
            value /= 1024;
            index++;
        }

        return $"{value:0.#} {units[index]}";
    }

    private async Task OpenPackageFolderAsync()
    {
        if (_lastPackage is null)
        {
            return;
        }

        var folderPath = Path.GetDirectoryName(_lastPackage.PackagePath);
        if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
        {
            return;
        }

        var folder = await StorageFolder.GetFolderFromPathAsync(folderPath);
        await Launcher.LaunchFolderAsync(folder);
    }

    private void CopyPackagePath()
    {
        if (_lastPackage is null)
        {
            return;
        }

        var data = new DataPackage();
        data.SetText(_lastPackage.PackagePath);
        Clipboard.SetContent(data);
        ToastService.Show(AppLocalizer.T("反馈包路径已复制", "Package path copied"), ToastKind.Success);
    }

    private void CopyFeedbackCode()
    {
        var code = FeedbackCode.Normalize(_feedbackCodeBox.Text);
        if (!FeedbackCode.IsValid(code))
        {
            RefreshFeedbackCode();
            code = _feedbackCodeBox.Text;
        }

        var data = new DataPackage();
        data.SetText(code);
        Clipboard.SetContent(data);
        ToastService.Show(AppLocalizer.T("反馈编号已复制", "Feedback code copied"), ToastKind.Success);
    }
}
