<?php

declare(strict_types=1);

namespace App\Filament\Pages;

use App\Enums\SupportCenter\HostSystemUpdateExecutionStatus;
use App\Enums\SupportCenter\HostSystemUpdateRecommendedMethod;
use App\Exceptions\SupportCenter\HostSystemUpdateExecutionException;
use App\Exceptions\SupportCenter\HostSystemUpdateRecoveryException;
use App\Exceptions\SupportCenter\SupportCenterException;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Concerns\RegistersDberpNavigationWhenAccessible;
use App\Filament\Pages\Concerns\InteractsWithDberpNavigationGroupBreadcrumbs;
use App\Filament\Support\DberpFilamentInfolistIconResolver;
use App\Models\HostSystemUpdateCheck;
use App\Models\HostSystemUpdateExecution;
use App\Services\DberpPermissionService;
use App\Services\DberpSystemUpdateNoticeService;
use App\Services\SupportCenter\HostSystemUpdateBrowserFailureFinalizer;
use App\Services\SupportCenter\HostSystemUpdateCheckService;
use App\Services\SupportCenter\HostSystemUpdateEntitlementGate;
use App\Services\SupportCenter\HostSystemUpdateOneClickOrchestrator;
use App\Services\SupportCenter\HostSystemUpdateRollbackService;
use App\Services\SupportCenter\HostSystemUpdateStepProgressStore;
use App\Services\SupportCenter\HostSystemUpdateStepRunner;
use App\Support\DberpMaintenanceDownExceptPaths;
use App\Support\HostSystemUpdateCenterDisplay;
use BackedEnum;
use DomainException;
use Filament\Actions\Action;
use Filament\Infolists\Components\TextEntry;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\EmbeddedSchema;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\View as SchemaView;
use Filament\Schemas\Schema;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Facades\Auth;
use Throwable;
use UnitEnum;

/**
 * @property-read Schema $content
 * @property-read Schema $infolist
 */
final class HostSystemUpdateCenterPage extends Page
{
    use InteractsWithDberpNavigationGroupBreadcrumbs;
    use InteractsWithDberpPermissions;
    use RegistersDberpNavigationWhenAccessible;

    protected static ?string $slug = DberpMaintenanceDownExceptPaths::UPDATE_CENTER_PAGE_SLUG;

    protected static ?int $navigationSort = 83;

    public bool $updateInProgress = false;

    public bool $updateProgressPanelVisible = false;

    public int $updateProgressPanelPollAttempts = 0;

    public ?string $updateSessionId = null;

    private const UPDATE_PROGRESS_PANEL_MAX_POLL_ATTEMPTS = 60;

    private const UPDATE_PROGRESS_WATCHDOG_SECONDS = 8;

    public static function getNavigationGroup(): string|UnitEnum|null
    {
        return __('dberp.nav.system');
    }

    public static function getNavigationLabel(): string
    {
        return __('dberp.labels.host_system_update_center');
    }

    public static function getNavigationIcon(): string|BackedEnum|Htmlable|null
    {
        return null;
    }

    public static function canAccess(): bool
    {
        return self::allowsPermission(DberpPermissionService::VIEW_HOST_SYSTEM_UPDATE);
    }

    public static function canCheckUpdate(): bool
    {
        return self::allowsPermission(DberpPermissionService::CHECK_HOST_SYSTEM_UPDATE);
    }

    public static function canDownloadPackage(): bool
    {
        return self::allowsPermission(DberpPermissionService::DOWNLOAD_HOST_SYSTEM_UPDATE);
    }

    public static function canExecuteUpdate(): bool
    {
        return self::allowsPermission(DberpPermissionService::EXECUTE_HOST_SYSTEM_UPDATE);
    }

    public static function canRollbackUpdate(): bool
    {
        return self::allowsPermission(DberpPermissionService::ROLLBACK_HOST_SYSTEM_UPDATE);
    }

    public static function canRunOneClickUpdate(): bool
    {
        return self::canCheckUpdate()
            && self::canDownloadPackage()
            && self::canExecuteUpdate();
    }

    public function canShowOneClickUpdateAction(): bool
    {
        if (! self::canRunOneClickUpdate()) {
            return false;
        }

        $display = app(HostSystemUpdateCenterDisplay::class);

        if (! $display->hasUpdateAvailable()) {
            return false;
        }

        $gate = app(HostSystemUpdateEntitlementGate::class);

        return $gate->canCheckUpdate() && $gate->canDownloadPackage();
    }

    public function getTitle(): string|Htmlable
    {
        return __('dberp.system_update_center.page_title');
    }

    public function getSubheading(): string|Htmlable|null
    {
        return __('dberp.system_update_center.page_intro');
    }

    /**
     * @return array<Action>
     */
    protected function getHeaderActions(): array
    {
        $display = app(HostSystemUpdateCenterDisplay::class);
        $actions = [];

        if (self::canCheckUpdate()) {
            $actions[] = Action::make('checkForUpdate')
                ->label(__('dberp.system_update_center.actions.check_update'))
                ->icon('heroicon-o-arrow-path')
                ->color('gray')
                ->disabled(fn (): bool => $this->isUpdateFlowBlockingUi())
                ->action(fn (): mixed => $this->refreshOfficialStatus());
        }

        if (self::canRunOneClickUpdate()) {
            $actions[] = $this->makeRunOneClickUpdateAction();
        }

        return $actions;
    }

    public function content(Schema $schema): Schema
    {
        return $schema->components([
            Section::make(__('dberp.system_update_center.sections.update_in_progress'))
                ->icon('heroicon-o-arrow-path')
                ->iconColor('primary')
                ->schema([
                    SchemaView::make('components.dberp.system-update.progress-panel')
                        ->viewData(fn (): array => $this->updateProgressPanelViewData())
                        ->columnSpanFull(),
                ])
                ->visible(fn (): bool => $this->shouldShowUpdateProgressPanel()),
            Section::make(__('dberp.system_update_notice.panel.title'))
                ->icon('heroicon-o-bell-alert')
                ->iconColor('primary')
                ->schema([
                    SchemaView::make('components.dberp.system-update.local-notice-panel')
                        ->viewData(fn (): array => [
                            'panel' => $this->systemUpdateNoticePanelData(),
                        ])
                        ->columnSpanFull(),
                ])
                ->footer([
                    Actions::make($this->systemUpdateNoticePanelActions()),
                ])
                ->visible(fn (): bool => $this->systemUpdateNoticePanelData() !== null),
            Section::make(__('dberp.system_update_center.sections.update_environment'))
                ->icon('heroicon-o-server-stack')
                ->iconColor('primary')
                ->collapsible()
                ->collapsed(fn (): bool => app(HostSystemUpdateCenterDisplay::class)->recommendedUpdateMethod()
                    === HostSystemUpdateRecommendedMethod::BrowserAvailable)
                ->schema([
                    SchemaView::make('components.dberp.system-update.update-environment-hub')
                        ->viewData(fn (): array => [
                            'panel' => app(HostSystemUpdateCenterDisplay::class)->updateEnvironmentHubPanelData(),
                        ])
                        ->columnSpanFull(),
                ])
                ->visible(fn (): bool => self::canRunOneClickUpdate()
                    && app(HostSystemUpdateCenterDisplay::class)->updateEnvironmentHubPanelData() !== null),
            EmbeddedSchema::make('infolist'),
            Section::make(__('dberp.system_update_center.sections.recovery'))
                ->schema([
                    TextEntry::make('recovery_hint')
                        ->label(__('dberp.system_update_center.rows.recovery_hint'))
                        ->state(fn (): string => (string) __('dberp.system_update_center.workflow.recovery_hint'))
                        ->columnSpanFull(),
                ])
                ->footer([
                    Actions::make($this->recoveryActions()),
                ])
                ->visible(fn (): bool => self::canRollbackUpdate()
                    && app(HostSystemUpdateCenterDisplay::class)->hasRollbackAvailable()),
        ]);
    }

    private function makeRunOneClickUpdateAction(): Action
    {
        $display = app(HostSystemUpdateCenterDisplay::class);

        return Action::make('runOneClickUpdate')
            ->label(__('dberp.system_update_center.actions.update_now'))
            ->icon('heroicon-o-arrow-up-circle')
            ->color('primary')
            ->requiresConfirmation()
            ->modalHeading(__('dberp.system_update_center.confirm.update_now_heading'))
            ->modalDescription(__('dberp.system_update_center.confirm.update_now_body'))
            ->visible(fn (): bool => $this->canShowOneClickUpdateAction())
            ->disabled(fn (): bool => $this->isUpdateFlowBlockingUi()
                || $display->oneClickUnavailableReason() !== null)
            ->action(fn (): mixed => $this->runOneClickUpdate());
    }

    /**
     * @return list<Action>
     */
    private function recoveryActions(): array
    {
        return [
            Action::make('rollbackUpdate')
                ->label(__('dberp.system_update_center.actions.rollback'))
                ->icon('heroicon-o-arrow-uturn-left')
                ->color('danger')
                ->requiresConfirmation()
                ->modalHeading(__('dberp.system_update_center.confirm.rollback_heading'))
                ->modalDescription(__('dberp.system_update_center.confirm.rollback_body'))
                ->disabled(fn (): bool => $this->isUpdateFlowBlockingUi())
                ->action(fn (): mixed => $this->rollbackUpdate()),
        ];
    }

    public function defaultInfolist(Schema $schema): Schema
    {
        if (! $schema->hasCustomColumns()) {
            $schema->columns(1);
        }

        return $schema
            ->inlineLabel(false)
            ->record(null);
    }

    public function infolist(Schema $schema): Schema
    {
        $display = app(HostSystemUpdateCenterDisplay::class);

        return $schema->components([
            Section::make(__('dberp.system_update_center.sections.overview'))
                ->icon(DberpFilamentInfolistIconResolver::section('update'))
                ->iconColor('primary')
                ->schema([
                    TextEntry::make('current_version')
                        ->label(__('dberp.system_update_center.rows.current_version'))
                        ->state($display->displayVersion())
                        ->badge()
                        ->color('primary')
                        ->copyable(),
                    TextEntry::make('latest_version')
                        ->label(__('dberp.system_update_center.rows.latest_version'))
                        ->state($display->latestVersionLabel() ?? (string) __('dberp.system_update_center.values.unknown_latest'))
                        ->badge()
                        ->color('info'),
                    TextEntry::make('update_available')
                        ->label(__('dberp.system_update_center.rows.update_available'))
                        ->state($display->updateAvailableLabel())
                        ->badge()
                        ->color(fn (): string => $display->updateAvailableBadgeColor()),
                    TextEntry::make('last_checked_at')
                        ->label(__('dberp.system_update_center.rows.last_checked_at'))
                        ->state($display->lastCheckedAtLabel() ?? (string) __('dberp.system_update_center.values.never_checked')),
                    TextEntry::make('release_notes')
                        ->label(__('dberp.system_update_center.rows.release_notes'))
                        ->state($display->releaseNotesSummary())
                        ->visible(fn (): bool => filled($display->releaseNotesSummary()))
                        ->extraAttributes(['class' => 'whitespace-pre-line leading-relaxed'])
                        ->columnSpanFull(),
                    TextEntry::make('workflow_hint')
                        ->label(__('dberp.system_update_center.rows.guidance'))
                        ->state($display->workflowHint())
                        ->columnSpanFull(),
                    TextEntry::make('maintenance_notice')
                        ->label(__('dberp.system_update_center.rows.maintenance_notice'))
                        ->state($display->maintenanceNotice())
                        ->color('warning')
                        ->columnSpanFull(),
                    TextEntry::make('unavailable_reason')
                        ->label(__('dberp.system_update_center.rows.unavailable_reason'))
                        ->state($display->oneClickUnavailableReason())
                        ->color('warning')
                        ->visible(fn (): bool => filled($display->oneClickUnavailableReason()))
                        ->columnSpanFull(),
                    TextEntry::make('environment_blocking_reason')
                        ->label(__('dberp.system_update_center.rows.environment_blocking_reason'))
                        ->state($display->environmentBlockingReason())
                        ->color('danger')
                        ->visible(fn (): bool => ! $display->canRunBrowserUpdate()
                            && self::canRunOneClickUpdate())
                        ->columnSpanFull(),
                    TextEntry::make('last_check_message')
                        ->label(__('dberp.system_update_center.rows.last_check_message'))
                        ->state($display->lastCheckMessage())
                        ->color('danger')
                        ->visible(fn (): bool => filled($display->lastCheckMessage()))
                        ->columnSpanFull(),
                ])
                ->columns(2),
            Section::make(__('dberp.system_update_center.sections.latest_result'))
                ->schema([
                    TextEntry::make('latest_result')
                        ->label(__('dberp.system_update_center.rows.latest_result'))
                        ->state($display->latestUpdateResultLabel())
                        ->badge()
                        ->color(fn (): string => $display->latestUpdateResultBadgeColor()),
                    TextEntry::make('latest_result_detail')
                        ->label(__('dberp.system_update_center.rows.latest_result_detail'))
                        ->state($display->latestUpdateResultDetail())
                        ->visible(fn (): bool => filled($display->latestUpdateResultDetail()))
                        ->columnSpanFull(),
                    SchemaView::make('components.dberp.system-update.failure-recovery-panel')
                        ->viewData(fn (): array => [
                            'panel' => $display->failureRecoveryPanelData(),
                        ])
                        ->visible(fn (): bool => $display->failureRecoveryPanelData() !== null)
                        ->columnSpanFull(),
                    TextEntry::make('in_progress_notice')
                        ->label(__('dberp.system_update_center.rows.in_progress_notice'))
                        ->state($display->syncExecutionLimitationNote())
                        ->color('warning')
                        ->visible(fn (): bool => filled($display->syncExecutionLimitationNote())
                            && ! $this->shouldShowUpdateProgressPanel())
                        ->columnSpanFull(),
                ])
                ->columns(2),
        ]);
    }

    public function runOneClickUpdate(): void
    {
        if (! self::canRunOneClickUpdate()) {
            $this->notifyOperationDenied();

            return;
        }

        if ($this->isUpdateFlowBlockingUi()) {
            Notification::make()
                ->warning()
                ->title(__('dberp.system_update_center.notifications.update_in_progress_title'))
                ->body(__('dberp.system_update_center.notifications.update_in_progress_body'))
                ->send();

            return;
        }

        $display = app(HostSystemUpdateCenterDisplay::class);

        if (! $display->canRunBrowserUpdate()) {
            Notification::make()
                ->danger()
                ->title(__('dberp.system_update_center.errors.environment_not_ready'))
                ->body($display->environmentBlockingReason()
                    ?? (string) __('dberp.system_update_center.errors.environment_not_ready'))
                ->send();

            return;
        }

        $this->updateInProgress = true;
        $this->updateProgressPanelVisible = true;
        $this->updateProgressPanelPollAttempts = 0;
        $this->scrollToUpdateProgressPanel();

        try {
            $this->updateSessionId = app(HostSystemUpdateOneClickOrchestrator::class)->beginSteppedUpdate();
            $this->advanceUpdateStep();
        } catch (SupportCenterException|HostSystemUpdateExecutionException|HostSystemUpdateRecoveryException|DomainException $exception) {
            $message = $exception instanceof SupportCenterException
                || $exception instanceof HostSystemUpdateExecutionException
                || $exception instanceof HostSystemUpdateRecoveryException
                ? $exception->userFacingMessage()
                : $exception->getMessage();

            $this->finishUpdateFlow(
                failed: true,
                body: $message,
            );
        } catch (Throwable $exception) {
            report($exception);

            $this->finishUpdateFlow(
                failed: true,
                body: (string) __('dberp.system_update_center.notifications.update_now_failed_body'),
            );
        }
    }

    public function advanceUpdateStep(): void
    {
        if (! $this->updateInProgress || $this->updateSessionId === null) {
            return;
        }

        try {
            $result = app(HostSystemUpdateStepRunner::class)->runNextStep($this->updateSessionId);

            if ($result->terminal) {
                $this->finishUpdateFlow(
                    failed: $result->failed,
                    body: $result->userMessage,
                    execution: $result->execution,
                );

                return;
            }

            $this->scheduleNextUpdateStep();
        } catch (SupportCenterException|HostSystemUpdateExecutionException|HostSystemUpdateRecoveryException|DomainException $exception) {
            $message = $exception instanceof SupportCenterException
                || $exception instanceof HostSystemUpdateExecutionException
                || $exception instanceof HostSystemUpdateRecoveryException
                ? $exception->userFacingMessage()
                : $exception->getMessage();

            $this->finishUpdateFlow(failed: true, body: $message);
        } catch (Throwable $exception) {
            report($exception);

            $this->finishUpdateFlow(
                failed: true,
                body: (string) __('dberp.system_update_center.notifications.update_now_failed_body'),
            );
        }
    }

    private function scheduleNextUpdateStep(): void
    {
        if (! $this->updateInProgress) {
            return;
        }

        $this->js('setTimeout(() => { $wire.advanceUpdateStep() }, 250)');
    }

    /**
     * 分步更新进行中看门狗：检测会话丢失、库内已失败/已完成但 Livewire 未收尾的情况。
     */
    public function watchdogBrowserUpdateStep(): void
    {
        if (! $this->updateInProgress) {
            return;
        }

        $display = app(HostSystemUpdateCenterDisplay::class);
        $execution = $display->latestExecution();
        $sessionId = $this->updateSessionId;

        if ($sessionId === null) {
            if ($execution instanceof HostSystemUpdateExecution) {
                $status = (string) ($execution->status ?? '');

                if ($status === HostSystemUpdateExecutionStatus::Completed->value) {
                    $this->finishUpdateFlow(failed: false, execution: $execution);

                    return;
                }

                if (in_array($status, [
                    HostSystemUpdateExecutionStatus::Failed->value,
                    HostSystemUpdateExecutionStatus::RollbackRequired->value,
                    HostSystemUpdateExecutionStatus::RollbackFailed->value,
                ], true)) {
                    $this->finishUpdateFlow(
                        failed: true,
                        body: (string) ($execution->error_message
                            ?? __('dberp.system_update_center.errors.browser_update_interrupted')),
                        execution: $execution,
                    );

                    return;
                }
            }

            app(HostSystemUpdateBrowserFailureFinalizer::class)->finalize(null, $execution);
            $this->finishUpdateFlow(
                failed: true,
                body: (string) __('dberp.system_update_center.errors.browser_update_interrupted'),
                execution: $execution,
            );

            return;
        }

        $progress = app(HostSystemUpdateStepProgressStore::class)->read($sessionId);

        if ($progress === null) {
            app(HostSystemUpdateBrowserFailureFinalizer::class)->finalize($sessionId, $execution);
            $this->finishUpdateFlow(
                failed: true,
                body: (string) __('dberp.system_update_center.errors.browser_update_interrupted'),
                execution: $execution,
            );

            return;
        }

        if ($progress->terminal) {
            $this->finishUpdateFlow(
                failed: $progress->failed,
                body: $progress->errorMessage,
                execution: $execution,
            );

            return;
        }

        if ($execution instanceof HostSystemUpdateExecution) {
            $status = (string) ($execution->status ?? '');

            if ($status === HostSystemUpdateExecutionStatus::Completed->value) {
                $this->finishUpdateFlow(failed: false, execution: $execution);

                return;
            }

            if (in_array($status, [
                HostSystemUpdateExecutionStatus::Failed->value,
                HostSystemUpdateExecutionStatus::RollbackRequired->value,
                HostSystemUpdateExecutionStatus::RollbackFailed->value,
            ], true)) {
                app(HostSystemUpdateBrowserFailureFinalizer::class)->finalize($sessionId, $execution);
                $this->finishUpdateFlow(
                    failed: true,
                    body: (string) ($execution->error_message ?? $progress->errorMessage),
                    execution: $execution,
                );
            }
        }
    }

    private function finishUpdateFlow(
        bool $failed,
        ?string $body = null,
        ?HostSystemUpdateExecution $execution = null,
    ): void {
        $sessionId = $this->updateSessionId;

        $this->updateInProgress = false;
        $this->updateSessionId = null;

        if ($failed) {
            app(HostSystemUpdateBrowserFailureFinalizer::class)->finalize($sessionId, $execution);

            $this->updateProgressPanelVisible = false;
            $this->updateProgressPanelPollAttempts = 0;

            Notification::make()
                ->danger()
                ->title(__('dberp.system_update_center.notifications.update_now_failed_title'))
                ->body($body ?? (string) __('dberp.system_update_center.notifications.update_now_failed_body'))
                ->send();

            return;
        }

        $status = (string) ($execution?->status ?? HostSystemUpdateExecutionStatus::Completed->value);

        if ($status === HostSystemUpdateExecutionStatus::Completed->value) {
            Notification::make()
                ->success()
                ->title(__('dberp.system_update_center.notifications.update_now_success_title'))
                ->body(__('dberp.system_update_center.notifications.update_now_success_body'))
                ->send();

            $this->beginUpdateProgressPanelDismissalPolling();

            return;
        }

        $this->updateProgressPanelVisible = false;
        $this->updateProgressPanelPollAttempts = 0;

        Notification::make()
            ->danger()
            ->title(__('dberp.system_update_center.notifications.update_now_failed_title'))
            ->body((string) ($execution?->error_message
                ?? $body
                ?? __('dberp.system_update_center.notifications.update_now_failed_body')))
            ->send();
    }

    public function pollUpdateProgressPanel(): void
    {
        if (! $this->updateProgressPanelVisible || $this->updateInProgress) {
            return;
        }

        $this->updateProgressPanelPollAttempts++;

        if (
            app(HostSystemUpdateCenterDisplay::class)->isReadyToDismissUpdateProgressPanel()
            || $this->updateProgressPanelPollAttempts >= self::UPDATE_PROGRESS_PANEL_MAX_POLL_ATTEMPTS
        ) {
            $this->dismissUpdateProgressPanel();
        }
    }

    public function dismissUpdateProgressPanel(): void
    {
        if ($this->updateInProgress) {
            return;
        }

        $this->updateProgressPanelVisible = false;
        $this->updateProgressPanelPollAttempts = 0;

        $this->redirect(self::getUrl(), navigate: true);
    }

    private function beginUpdateProgressPanelDismissalPolling(): void
    {
        $this->pollUpdateProgressPanel();

        $this->js('setTimeout(() => { $wire.pollUpdateProgressPanel() }, 400)');
    }

    private function isUpdateFlowBlockingUi(): bool
    {
        return $this->updateInProgress
            || $this->updateProgressPanelVisible
            || app(HostSystemUpdateCenterDisplay::class)->isUpdateRunning();
    }

    public function refreshOfficialStatus(): void
    {
        if (! self::canCheckUpdate()) {
            $this->notifyOperationDenied();

            return;
        }

        if (! app(HostSystemUpdateEntitlementGate::class)->canCheckUpdate()) {
            $this->notifyEntitlementDenied(app(HostSystemUpdateEntitlementGate::class)->checkReason());

            return;
        }

        try {
            $check = app(HostSystemUpdateCheckService::class)->check();

            Notification::make()
                ->success()
                ->title(__('dberp.system_update_center.notifications.check_success_title'))
                ->body($this->checkSuccessNotificationBody($check))
                ->send();

            $this->redirect(self::getUrl(), navigate: true);

            return;
        } catch (SupportCenterException $exception) {
            Notification::make()
                ->danger()
                ->title(__('dberp.system_update_center.notifications.check_failed_title'))
                ->body($exception->userFacingMessage())
                ->send();
        }
    }

    public function rollbackUpdate(): void
    {
        if (! self::canRollbackUpdate()) {
            $this->notifyOperationDenied();

            return;
        }

        $execution = app(HostSystemUpdateCenterDisplay::class)->latestExecution();

        if (! $execution instanceof HostSystemUpdateExecution
            || (string) ($execution->status ?? '') !== HostSystemUpdateExecutionStatus::RollbackRequired->value) {
            Notification::make()
                ->warning()
                ->title(__('dberp.system_update_center.notifications.rollback_unavailable_title'))
                ->body(__('dberp.system_update_center.notifications.rollback_unavailable_body'))
                ->send();

            return;
        }

        try {
            app(HostSystemUpdateRollbackService::class)->rollback($execution);

            Notification::make()
                ->success()
                ->title(__('dberp.system_update_center.notifications.rollback_success_title'))
                ->body(__('dberp.system_update_center.notifications.rollback_success_body'))
                ->send();
        } catch (HostSystemUpdateRecoveryException $exception) {
            Notification::make()
                ->danger()
                ->title(__('dberp.system_update_center.notifications.rollback_failed_title'))
                ->body($exception->userFacingMessage())
                ->send();
        }
    }

    private function shouldShowUpdateProgressPanel(): bool
    {
        return $this->updateProgressPanelVisible
            || $this->updateInProgress
            || app(HostSystemUpdateCenterDisplay::class)->isUpdateRunning();
    }

    /**
     * @return array{
     *     progressPercent: int,
     *     currentPhase: string,
     *     progressLabel: string,
     *     notice: string,
     *     logEntries: list<array{time: string, step_label: string, status_label: string, status_color: string, message: string}>,
     *     logsEmptyMessage: string,
     *     logsHeading: string,
     *     pollForDismissal: bool,
     * }
     */
    private function updateProgressPanelViewData(): array
    {
        $display = app(HostSystemUpdateCenterDisplay::class);

        return [
            'progressPercent' => $display->executionProgressPercent(),
            'currentPhase' => $this->resolveUpdateProgressPhaseLabel($display),
            'progressLabel' => $display->executionProgressLabel(),
            'notice' => (string) __('dberp.system_update_center.workflow.update_in_progress_notice'),
            'logEntries' => $display->recentExecutionLogEntries(),
            'logsEmptyMessage' => (string) __('dberp.system_update_center.values.no_execution_logs'),
            'logsHeading' => (string) __('dberp.system_update_center.rows.execution_process_log'),
            'pollForDismissal' => $this->updateProgressPanelVisible && ! $this->updateInProgress,
            'pollWhileRunning' => $this->updateInProgress,
            'pollWhileRunningInterval' => self::UPDATE_PROGRESS_WATCHDOG_SECONDS.'s',
            'terminal' => $display->updateProgressTerminalPanelData(),
        ];
    }

    private function resolveUpdateProgressPhaseLabel(HostSystemUpdateCenterDisplay $display): string
    {
        $currentStep = trim((string) ($display->latestExecution()?->current_step ?? ''));

        if ($currentStep !== '') {
            return $display->executionStepLabel();
        }

        return (string) __('dberp.system_update_center.workflow.preparing_update');
    }

    private function scrollToUpdateProgressPanel(): void
    {
        $this->js('document.getElementById("dberp-update-progress-panel")?.scrollIntoView({ behavior: "smooth", block: "start" })');
    }

    private function checkSuccessNotificationBody(HostSystemUpdateCheck $check): string
    {
        if ($check->update_available) {
            return (string) __('dberp.system_update_center.notifications.check_success_body_has_update');
        }

        return (string) __('dberp.system_update_center.notifications.check_success_body_up_to_date');
    }

    private function notifyOperationDenied(): void
    {
        Notification::make()
            ->danger()
            ->title(__('dberp.system_update_center.notifications.permission_denied_title'))
            ->body(__('dberp.system_update_center.notifications.permission_denied_body'))
            ->send();
    }

    private function notifyEntitlementDenied(string $reason): void
    {
        Notification::make()
            ->warning()
            ->title(__('dberp.system_update_center.notifications.entitlement_denied_title'))
            ->body($reason)
            ->send();
    }

    /**
     * @return array<string, mixed>|null
     */
    private function systemUpdateNoticePanelData(): ?array
    {
        return app(DberpSystemUpdateNoticeService::class)->panelViewDataFor(Auth::user());
    }

    /**
     * @return list<Action>
     */
    private function systemUpdateNoticePanelActions(): array
    {
        $panel = $this->systemUpdateNoticePanelData();

        if ($panel === null) {
            return [];
        }

        $noticeId = (int) $panel['notice_id'];

        return [
            Action::make('markSystemUpdateNoticeRead')
                ->label(__('dberp.system_update_notice.actions.mark_read'))
                ->icon('heroicon-o-check')
                ->color('gray')
                ->action(fn (): mixed => $this->markSystemUpdateNoticeAsRead($noticeId)),
            Action::make('dismissSystemUpdateNotice')
                ->label(__('dberp.system_update_notice.actions.dismiss'))
                ->icon('heroicon-o-x-mark')
                ->color('gray')
                ->requiresConfirmation()
                ->modalHeading(__('dberp.system_update_notice.confirm.dismiss_heading'))
                ->modalDescription(__('dberp.system_update_notice.confirm.dismiss'))
                ->action(fn (): mixed => $this->dismissSystemUpdateNotice($noticeId)),
        ];
    }

    public function markSystemUpdateNoticeAsRead(int $noticeId): void
    {
        $user = Auth::user();

        if ($user === null) {
            return;
        }

        if (! app(DberpSystemUpdateNoticeService::class)->markAsRead($user, $noticeId)) {
            return;
        }

        Notification::make()
            ->success()
            ->title(__('dberp.system_update_notice.messages.marked_read'))
            ->send();
    }

    public function dismissSystemUpdateNotice(int $noticeId): void
    {
        $user = Auth::user();

        if ($user === null) {
            return;
        }

        if (! app(DberpSystemUpdateNoticeService::class)->dismiss($user, $noticeId)) {
            return;
        }

        Notification::make()
            ->success()
            ->title(__('dberp.system_update_notice.messages.dismissed'))
            ->send();

        $this->redirect(self::getUrl(), navigate: true);
    }
}
