<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Services\SupportCenter;

use App\Exceptions\SupportCenter\HostSystemUpdateFileExecutionException;
use App\Exceptions\SupportCenter\HostSystemUpdateManifestException;
use App\Exceptions\SupportCenter\HostSystemUpdatePostApplyException;
use App\Exceptions\SupportCenter\HostSystemUpdateRecoveryException;
use App\Exceptions\SupportCenter\HostSystemUpdateStagingException;
use App\Exceptions\SupportCenter\SupportCenterException;
use App\Models\HostSystemAuthorization;
use App\Models\HostSystemUpdateBackup;
use App\Models\HostSystemUpdateCheck;
use App\Models\HostSystemUpdateExecution;
use App\Models\HostSystemUpdatePackage;
use App\Services\DberpAuditService;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;

/**
 * Support Center 关键操作审计：仅写入业务安全字段，不含密钥与原始接入码。
 */
final class SupportCenterAuditLogger
{
    public const ACTION_SITE_ACCESS_CONFIRM_SUCCEEDED = 'dberp.support_center.site_access_confirm.succeeded';

    public const ACTION_SITE_ACCESS_CONFIRM_FAILED = 'dberp.support_center.site_access_confirm.failed';

    public const ACTION_SITE_BINDING_STATUS_REFRESHED = 'dberp.support_center.site_binding_status.refreshed';

    public const ACTION_SITE_BINDING_STATUS_REFRESH_FAILED = 'dberp.support_center.site_binding_status.refresh_failed';

    public const ACTION_SITE_PRESENCE_REPORTED = 'dberp.support_center.site_presence.reported';

    public const ACTION_SITE_PRESENCE_FAILED = 'dberp.support_center.site_presence.failed';

    public const ACTION_AUTHORIZATION_SYNC_STARTED = 'dberp.support_center.authorization_sync.started';

    public const ACTION_AUTHORIZATION_SYNC_COMPLETED = 'dberp.support_center.authorization_sync.completed';

    public const ACTION_AUTHORIZATION_SYNC_FAILED = 'dberp.support_center.authorization_sync.failed';

    public const ACTION_CONNECTIVITY_BLOCKED = 'dberp.support_center.connectivity.blocked';

    public const ACTION_SYSTEM_UPDATE_CHECK_STARTED = 'dberp.support_center.system_update_check.started';

    public const ACTION_SYSTEM_UPDATE_CHECK_COMPLETED = 'dberp.support_center.system_update_check.completed';

    public const ACTION_SYSTEM_UPDATE_CHECK_FAILED = 'dberp.support_center.system_update_check.failed';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_TOKEN_REQUESTED = 'dberp.support_center.system_update_package.download_token_requested';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_STARTED = 'dberp.support_center.system_update_package.download_started';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_COMPLETED = 'dberp.support_center.system_update_package.download_completed';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_FAILED = 'dberp.support_center.system_update_package.download_failed';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_VERIFICATION_COMPLETED = 'dberp.support_center.system_update_package.verification_completed';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_VERIFICATION_FAILED = 'dberp.support_center.system_update_package.verification_failed';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_SIGNATURE_VERIFIED = 'dberp.support_center.system_update_package.signature_verified';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_SIGNATURE_SKIPPED = 'dberp.support_center.system_update_package.signature_skipped';

    public const ACTION_SYSTEM_UPDATE_PACKAGE_SIGNATURE_VERIFICATION_FAILED = 'dberp.support_center.system_update_package.signature_verification_failed';

    public const ACTION_SYSTEM_UPDATE_RESULT_REPORTED = 'dberp.support_center.system_update_result.reported';

    public const ACTION_SYSTEM_UPDATE_RESULT_REPORT_FAILED = 'dberp.support_center.system_update_result.report_failed';

    public const ACTION_SYSTEM_UPDATE_RESULT_REPORT_SKIPPED = 'dberp.support_center.system_update_result.report_skipped';

    public const ACTION_SYSTEM_UPDATE_MANIFEST_PARSING_STARTED = 'dberp.support_center.system_update_manifest.parsing_started';

    public const ACTION_SYSTEM_UPDATE_MANIFEST_PARSING_COMPLETED = 'dberp.support_center.system_update_manifest.parsing_completed';

    public const ACTION_SYSTEM_UPDATE_MANIFEST_PARSING_FAILED = 'dberp.support_center.system_update_manifest.parsing_failed';

    public const ACTION_SYSTEM_UPDATE_MANIFEST_VALIDATION_FAILED = 'dberp.support_center.system_update_manifest.validation_failed';

    public const ACTION_SYSTEM_UPDATE_EXECUTION_CREATED = 'dberp.support_center.system_update_execution.created';

    public const ACTION_SYSTEM_UPDATE_EXECUTION_STARTED = 'dberp.support_center.system_update_execution.started';

    public const ACTION_SYSTEM_UPDATE_EXECUTION_STATE_CHANGED = 'dberp.support_center.system_update_execution.state_changed';

    public const ACTION_SYSTEM_UPDATE_EXECUTION_FAILED = 'dberp.support_center.system_update_execution.failed';

    public const ACTION_SYSTEM_UPDATE_EXECUTION_CANCELLED = 'dberp.support_center.system_update_execution.cancelled';

    public const ACTION_SYSTEM_UPDATE_STAGING_EXTRACTION_STARTED = 'dberp.support_center.system_update_staging.extraction_started';

    public const ACTION_SYSTEM_UPDATE_STAGING_EXTRACTION_COMPLETED = 'dberp.support_center.system_update_staging.extraction_completed';

    public const ACTION_SYSTEM_UPDATE_STAGING_EXTRACTION_FAILED = 'dberp.support_center.system_update_staging.extraction_failed';

    public const ACTION_SYSTEM_UPDATE_BACKUP_STARTED = 'dberp.support_center.system_update_backup.started';

    public const ACTION_SYSTEM_UPDATE_BACKUP_COMPLETED = 'dberp.support_center.system_update_backup.completed';

    public const ACTION_SYSTEM_UPDATE_BACKUP_FAILED = 'dberp.support_center.system_update_backup.failed';

    public const ACTION_SYSTEM_UPDATE_FILE_REPLACEMENT_STARTED = 'dberp.support_center.system_update_file_replacement.started';

    public const ACTION_SYSTEM_UPDATE_FILE_REPLACEMENT_COMPLETED = 'dberp.support_center.system_update_file_replacement.completed';

    public const ACTION_SYSTEM_UPDATE_FILE_REPLACEMENT_FAILED = 'dberp.support_center.system_update_file_replacement.failed';

    public const ACTION_SYSTEM_UPDATE_FILE_DELETION_STARTED = 'dberp.support_center.system_update_file_deletion.started';

    public const ACTION_SYSTEM_UPDATE_FILE_DELETION_COMPLETED = 'dberp.support_center.system_update_file_deletion.completed';

    public const ACTION_SYSTEM_UPDATE_FILE_DELETION_FAILED = 'dberp.support_center.system_update_file_deletion.failed';

    public const ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_STARTED = 'dberp.support_center.system_update_vendor_replacement.started';

    public const ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_COMPLETED = 'dberp.support_center.system_update_vendor_replacement.completed';

    public const ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_DEFERRED = 'dberp.support_center.system_update_vendor_replacement.deferred';

    public const ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_FAILED = 'dberp.support_center.system_update_vendor_replacement.failed';

    public const ACTION_SYSTEM_UPDATE_MIGRATION_STARTED = 'dberp.support_center.system_update_migration.started';

    public const ACTION_SYSTEM_UPDATE_MIGRATION_COMPLETED = 'dberp.support_center.system_update_migration.completed';

    public const ACTION_SYSTEM_UPDATE_MIGRATION_FAILED = 'dberp.support_center.system_update_migration.failed';

    public const ACTION_SYSTEM_UPDATE_CACHE_CLEAR_STARTED = 'dberp.support_center.system_update_cache_clear.started';

    public const ACTION_SYSTEM_UPDATE_CACHE_CLEAR_COMPLETED = 'dberp.support_center.system_update_cache_clear.completed';

    public const ACTION_SYSTEM_UPDATE_CACHE_CLEAR_FAILED = 'dberp.support_center.system_update_cache_clear.failed';

    public const ACTION_SYSTEM_UPDATE_VERSION_WRITE_STARTED = 'dberp.support_center.system_update_version_write.started';

    public const ACTION_SYSTEM_UPDATE_VERSION_WRITE_COMPLETED = 'dberp.support_center.system_update_version_write.completed';

    public const ACTION_SYSTEM_UPDATE_VERSION_WRITE_FAILED = 'dberp.support_center.system_update_version_write.failed';

    public const ACTION_SYSTEM_UPDATE_FAILURE_CAPTURED = 'dberp.support_center.system_update_failure.captured';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_STARTED = 'dberp.support_center.system_update_rollback.started';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_FILE_RESTORE_COMPLETED = 'dberp.support_center.system_update_rollback.file_restore_completed';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_FILE_RESTORE_FAILED = 'dberp.support_center.system_update_rollback.file_restore_failed';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_ENV_RESTORE_COMPLETED = 'dberp.support_center.system_update_rollback.env_restore_completed';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_ENV_RESTORE_FAILED = 'dberp.support_center.system_update_rollback.env_restore_failed';

    public const ACTION_SYSTEM_UPDATE_MAINTENANCE_MODE_RESTORED = 'dberp.support_center.system_update_maintenance.restored';

    public const ACTION_SYSTEM_UPDATE_MAINTENANCE_MODE_RESTORE_FAILED = 'dberp.support_center.system_update_maintenance.restore_failed';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_COMPLETED = 'dberp.support_center.system_update_rollback.completed';

    public const ACTION_SYSTEM_UPDATE_ROLLBACK_FAILED = 'dberp.support_center.system_update_rollback.failed';

    public const ACTION_SYSTEM_UPDATE_EXECUTION_COMPLETED = 'dberp.support_center.system_update_execution.completed';

    public function __construct(
        private readonly DberpAuditService $auditService,
    ) {}

    /**
     * @param  array<string, mixed>  $normalized
     */
    public function logSiteAccessConfirmSucceeded(array $normalized, string $taskNo): void
    {
        $this->log(self::ACTION_SITE_ACCESS_CONFIRM_SUCCEEDED, [
            'operation' => 'site_onboarding_confirm',
            'result_status' => 'success',
            'task_no_masked' => self::maskIdentifier($taskNo),
            'site_no' => $this->nullableString($normalized['site_no'] ?? null),
            'binding_status' => $this->nullableString($normalized['binding_status'] ?? null),
        ]);
    }

    public function logSiteAccessConfirmFailed(string $taskNo, SupportCenterException $exception): void
    {
        $this->logFailure(
            self::ACTION_SITE_ACCESS_CONFIRM_FAILED,
            'site_onboarding_confirm',
            $exception,
            [
                'task_no_masked' => self::maskIdentifier($taskNo),
            ],
        );
    }

    /**
     * @param  array<string, mixed>  $normalized
     */
    public function logSiteBindingStatusRefreshed(array $normalized): void
    {
        $this->log(self::ACTION_SITE_BINDING_STATUS_REFRESHED, [
            'operation' => 'site_onboarding_status',
            'result_status' => 'success',
            'site_no' => $this->nullableString($normalized['site_no'] ?? null),
            'binding_status' => $this->nullableString($normalized['binding_status'] ?? null),
        ]);
    }

    public function logSiteBindingStatusRefreshFailed(SupportCenterException $exception): void
    {
        $this->logFailure(
            self::ACTION_SITE_BINDING_STATUS_REFRESH_FAILED,
            'site_onboarding_status',
            $exception,
        );
    }

    public function logSitePresenceReported(string $siteNo): void
    {
        $this->log(self::ACTION_SITE_PRESENCE_REPORTED, [
            'operation' => 'site_presence',
            'result_status' => 'success',
            'site_no' => $siteNo,
        ]);
    }

    public function logSitePresenceFailed(string $siteNo, SupportCenterException $exception): void
    {
        $this->logFailure(
            self::ACTION_SITE_PRESENCE_FAILED,
            'site_presence',
            $exception,
            [
                'site_no' => $siteNo,
            ],
        );
    }

    public function logAuthorizationSyncStarted(?string $siteNo, ?string $licenseNo): void
    {
        $this->log(self::ACTION_AUTHORIZATION_SYNC_STARTED, [
            'operation' => 'host_authorization_sync',
            'result_status' => 'started',
            'site_no' => $siteNo,
            'license_no' => $licenseNo,
        ], HostSystemAuthorization::singleton());
    }

    public function logAuthorizationSyncCompleted(?string $siteNo, ?string $licenseNo, bool $authorized): void
    {
        $this->log(self::ACTION_AUTHORIZATION_SYNC_COMPLETED, [
            'operation' => 'host_authorization_sync',
            'result_status' => 'success',
            'site_no' => $siteNo,
            'license_no' => $licenseNo,
            'authorized' => $authorized,
        ], HostSystemAuthorization::singleton());
    }

    public function logAuthorizationSyncFailed(
        ?string $siteNo,
        ?string $licenseNo,
        SupportCenterException $exception,
    ): void {
        $this->logFailure(
            self::ACTION_AUTHORIZATION_SYNC_FAILED,
            'host_authorization_sync',
            $exception,
            [
                'site_no' => $siteNo,
                'license_no' => $licenseNo,
            ],
            HostSystemAuthorization::singleton(),
        );
    }

    public function logConnectivityBlocked(string $operation, SupportCenterException $exception): void
    {
        $this->log(self::ACTION_CONNECTIVITY_BLOCKED, [
            'operation' => $operation,
            'result_status' => 'failed',
            'error_code' => $exception->errorCode(),
            'user_facing_message' => $exception->userFacingMessage(),
            'request_id' => $exception->requestId(),
        ]);
    }

    public function logSystemUpdateCheckStarted(?string $siteNo, ?string $licenseNo, string $releaseChannel): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_CHECK_STARTED, [
            'operation' => 'host_system_update_check',
            'result_status' => 'started',
            'site_no' => $siteNo,
            'license_no' => $licenseNo,
            'release_channel' => $releaseChannel,
        ], HostSystemUpdateCheck::singleton());
    }

    public function logSystemUpdateCheckCompleted(
        ?string $siteNo,
        ?string $licenseNo,
        bool $updateAvailable,
        ?string $latestVersion,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_CHECK_COMPLETED, [
            'operation' => 'host_system_update_check',
            'result_status' => 'success',
            'site_no' => $siteNo,
            'license_no' => $licenseNo,
            'update_available' => $updateAvailable,
            'latest_version' => $latestVersion,
        ], HostSystemUpdateCheck::singleton());
    }

    public function logSystemUpdateCheckFailed(
        ?string $siteNo,
        ?string $licenseNo,
        SupportCenterException $exception,
    ): void {
        $this->logFailure(
            self::ACTION_SYSTEM_UPDATE_CHECK_FAILED,
            'host_system_update_check',
            $exception,
            [
                'site_no' => $siteNo,
                'license_no' => $licenseNo,
            ],
            HostSystemUpdateCheck::singleton(),
        );
    }

    public function logSystemUpdatePackageDownloadTokenRequested(
        ?string $packageId,
        ?string $version,
        ?string $releaseChannel,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_TOKEN_REQUESTED, [
            'operation' => 'host_system_update_download_token',
            'result_status' => 'started',
            'package_id' => $packageId,
            'version' => $version,
            'release_channel' => $releaseChannel,
        ]);
    }

    public function logSystemUpdatePackageDownloadStarted(
        HostSystemUpdatePackage $package,
        ?string $requestId = null,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_STARTED, [
            'operation' => 'host_system_update_package_download',
            'result_status' => 'started',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'checksum' => $package->checksum,
            'checksum_algorithm' => $package->checksum_algorithm,
            'request_id' => $requestId,
        ], $package);
    }

    public function logSystemUpdatePackageDownloadCompleted(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_COMPLETED, [
            'operation' => 'host_system_update_package_download',
            'result_status' => 'success',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'checksum' => $package->checksum,
            'checksum_algorithm' => $package->checksum_algorithm,
            'local_size' => $package->local_size,
            'request_id' => $package->download_request_id,
        ], $package);
    }

    public function logSystemUpdatePackageDownloadFailed(
        ?string $packageId,
        ?string $version,
        ?string $releaseChannel,
        SupportCenterException $exception,
        ?HostSystemUpdatePackage $package = null,
    ): void {
        $this->logFailure(
            self::ACTION_SYSTEM_UPDATE_PACKAGE_DOWNLOAD_FAILED,
            'host_system_update_package_download',
            $exception,
            [
                'package_id' => $packageId,
                'version' => $version,
                'release_channel' => $releaseChannel,
            ],
            $package,
        );
    }

    public function logSystemUpdatePackageVerificationCompleted(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_VERIFICATION_COMPLETED, [
            'operation' => 'host_system_update_package_verification',
            'result_status' => 'success',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'checksum' => $package->checksum,
            'checksum_algorithm' => $package->checksum_algorithm,
            'local_size' => $package->local_size,
            'verified' => true,
        ], $package);
    }

    public function logSystemUpdatePackageVerificationFailed(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_VERIFICATION_FAILED, [
            'operation' => 'host_system_update_package_verification',
            'result_status' => 'failed',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'checksum' => $package->checksum,
            'checksum_algorithm' => $package->checksum_algorithm,
            'local_size' => $package->local_size,
            'verified' => false,
            'error_code' => $package->download_error_code,
            'user_facing_message' => $package->download_message,
        ], $package);
    }

    public function logSystemUpdatePackageSignatureVerified(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_SIGNATURE_VERIFIED, [
            'operation' => 'host_system_update_package_signature',
            'result_status' => 'success',
            'package_id' => $package->package_id,
            'version' => $package->version,
        ], $package);
    }

    public function logSystemUpdatePackageSignatureSkipped(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_SIGNATURE_SKIPPED, [
            'operation' => 'host_system_update_package_signature',
            'result_status' => 'skipped',
            'package_id' => $package->package_id,
            'version' => $package->version,
        ], $package);
    }

    public function logSystemUpdatePackageSignatureVerificationFailed(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_PACKAGE_SIGNATURE_VERIFICATION_FAILED, [
            'operation' => 'host_system_update_package_signature',
            'result_status' => 'failed',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'error_code' => $package->download_error_code,
            'user_facing_message' => $package->download_message,
        ], $package);
    }

    /**
     * @param  array<string, mixed>  $response
     */
    public function logSystemUpdateResultReported(
        HostSystemUpdateExecution $execution,
        string $kind,
        array $response,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_RESULT_REPORTED, [
            'operation' => 'host_system_update_result_report',
            'result_status' => 'success',
            'report_kind' => $kind,
            'execution_no' => $execution->execution_no,
            'package_id' => $execution->package_id,
            'request_id' => is_string($response['request_id'] ?? null) ? $response['request_id'] : null,
        ], $execution);
    }

    public function logSystemUpdateResultReportFailed(
        HostSystemUpdateExecution $execution,
        string $kind,
        \Throwable $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_RESULT_REPORT_FAILED, [
            'operation' => 'host_system_update_result_report',
            'result_status' => 'failed',
            'report_kind' => $kind,
            'execution_no' => $execution->execution_no,
            'package_id' => $execution->package_id,
            'exception_class' => $exception::class,
        ], $execution);
    }

    /**
     * @param  array<string, bool>  $identitySourcePresence
     */
    public function logSystemUpdateResultReportSkipped(
        HostSystemUpdateExecution $execution,
        string $kind,
        string $reason,
        array $identitySourcePresence = [],
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_RESULT_REPORT_SKIPPED, [
            'operation' => 'host_system_update_result_report',
            'result_status' => 'skipped',
            'report_kind' => $kind,
            'execution_no' => $execution->execution_no,
            'package_id' => $execution->package_id,
            'skip_reason' => $reason,
            'identity_source_presence' => $identitySourcePresence,
        ], $execution);
    }

    public function logSystemUpdateManifestParsingStarted(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_MANIFEST_PARSING_STARTED, [
            'operation' => 'host_system_update_manifest_parse',
            'result_status' => 'started',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
        ], $package);
    }

    public function logSystemUpdateManifestParsingCompleted(HostSystemUpdatePackage $package): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_MANIFEST_PARSING_COMPLETED, [
            'operation' => 'host_system_update_manifest_parse',
            'result_status' => 'success',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'manifest_status' => $package->manifest_status,
            'to_update_version' => $package->manifest['to_update_version'] ?? null,
        ], $package);
    }

    public function logSystemUpdateManifestParsingFailed(
        HostSystemUpdatePackage $package,
        HostSystemUpdateManifestException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MANIFEST_PARSING_FAILED, [
            'operation' => 'host_system_update_manifest_parse',
            'result_status' => 'failed',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'error_code' => $exception->errorCode(),
            'user_facing_message' => $exception->userFacingMessage(),
        ], $package);
    }

    public function logSystemUpdateManifestValidationFailed(
        HostSystemUpdatePackage $package,
        HostSystemUpdateManifestException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MANIFEST_VALIDATION_FAILED, [
            'operation' => 'host_system_update_manifest_validate',
            'result_status' => 'failed',
            'package_id' => $package->package_id,
            'version' => $package->version,
            'release_channel' => $package->release_channel,
            'error_code' => $exception->errorCode(),
            'user_facing_message' => $exception->userFacingMessage(),
        ], $package);
    }

    public function logSystemUpdateExecutionCreated(HostSystemUpdateExecution $execution): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_EXECUTION_CREATED, $this->executionAuditPayload($execution, [
            'operation' => 'host_system_update_execution_create',
            'result_status' => 'success',
        ]), $execution);
    }

    public function logSystemUpdateExecutionStarted(HostSystemUpdateExecution $execution): void
    {
        $this->log(self::ACTION_SYSTEM_UPDATE_EXECUTION_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_execution_start',
                'result_status' => 'started',
                'status' => $execution->status,
                'current_step' => $execution->current_step,
            ],
        ), $execution);
    }

    public function logSystemUpdateExecutionStateChanged(
        HostSystemUpdateExecution $execution,
        ?string $fromStatus = null,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_EXECUTION_STATE_CHANGED, $this->executionAuditPayload($execution, [
            'operation' => 'host_system_update_execution_state',
            'result_status' => 'changed',
            'from_status' => $fromStatus,
        ]), $execution);
    }

    public function logSystemUpdateExecutionFailed(
        HostSystemUpdateExecution $execution,
        string $errorCode,
        string $errorMessage,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_EXECUTION_FAILED, $this->executionAuditPayload($execution, [
            'operation' => 'host_system_update_execution',
            'result_status' => 'failed',
            'error_code' => $errorCode,
            'user_facing_message' => $errorMessage,
        ]), $execution);
    }

    public function logSystemUpdateExecutionCancelled(
        HostSystemUpdateExecution $execution,
        ?string $reason = null,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_EXECUTION_CANCELLED, $this->executionAuditPayload($execution, [
            'operation' => 'host_system_update_execution',
            'result_status' => 'cancelled',
            'user_facing_message' => $reason,
        ]), $execution);
    }

    public function logSystemUpdateStagingExtractionStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_STAGING_EXTRACTION_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_staging_extract',
                'result_status' => 'started',
                'package_id' => $package->package_id,
                'staging_relative_path' => HostSystemUpdateWorkspaceStorage::relativeFromStorage(
                    HostSystemUpdateWorkspaceStorage::stagingDirectory($execution->execution_no),
                ),
            ],
        ), $execution);
    }

    public function logSystemUpdateStagingExtractionCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        int $extractedCount,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_STAGING_EXTRACTION_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_staging_extract',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'extracted_count' => $extractedCount,
            ],
        ), $execution);
    }

    public function logSystemUpdateStagingExtractionFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdateStagingException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_STAGING_EXTRACTION_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_staging_extract',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateBackupStarted(
        HostSystemUpdateExecution $execution,
        string $backupType,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_BACKUP_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_backup',
                'result_status' => 'started',
                'backup_type' => $backupType,
                'backup_relative_path' => HostSystemUpdateWorkspaceStorage::relativeFromStorage(
                    HostSystemUpdateWorkspaceStorage::backupsDirectory($execution->execution_no),
                ),
            ],
        ), $execution);
    }

    public function logSystemUpdateBackupCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateBackup $backup,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_BACKUP_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_backup',
                'result_status' => 'success',
                'backup_no' => $backup->backup_no,
                'backup_type' => $backup->backup_type,
                'backup_size' => $backup->backup_size,
                'backup_relative_path' => $backup->backup_path,
                'file_count' => is_array($backup->included_paths) ? count($backup->included_paths) : 0,
            ],
        ), $execution);
    }

    public function logSystemUpdateBackupFailed(
        HostSystemUpdateExecution $execution,
        string $backupType,
        HostSystemUpdateStagingException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_BACKUP_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_backup',
                'result_status' => 'failed',
                'backup_type' => $backupType,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateFileReplacementStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        int $fileCount,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FILE_REPLACEMENT_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_file_replacement',
                'result_status' => 'started',
                'package_id' => $package->package_id,
                'file_count' => $fileCount,
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public function logSystemUpdateFileReplacementCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FILE_REPLACEMENT_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_file_replacement',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'replaced_count' => $summary['replaced_count'] ?? 0,
                'skipped_count' => $summary['skipped_count'] ?? 0,
            ],
        ), $execution);
    }

    public function logSystemUpdateFileReplacementFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdateFileExecutionException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FILE_REPLACEMENT_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_file_replacement',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateFileDeletionStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        int $fileCount,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FILE_DELETION_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_file_deletion',
                'result_status' => 'started',
                'package_id' => $package->package_id,
                'file_count' => $fileCount,
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public function logSystemUpdateFileDeletionCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FILE_DELETION_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_file_deletion',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'deleted_count' => $summary['deleted_count'] ?? 0,
                'skipped_count' => $summary['skipped_count'] ?? 0,
                'missing_count' => $summary['missing_count'] ?? 0,
            ],
        ), $execution);
    }

    public function logSystemUpdateFileDeletionFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdateFileExecutionException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FILE_DELETION_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_file_deletion',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateVendorReplacementStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        string $vendorStrategy,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_vendor_replacement',
                'result_status' => 'started',
                'package_id' => $package->package_id,
                'vendor_strategy' => $vendorStrategy,
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public function logSystemUpdateVendorReplacementCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        string $vendorStrategy,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_vendor_replacement',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'vendor_strategy' => $vendorStrategy,
                'replaced_count' => $summary['replaced_count'] ?? 0,
                'skipped_count' => $summary['skipped_count'] ?? 0,
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public function logSystemUpdateVendorReplacementDeferred(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        string $vendorStrategy,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_DEFERRED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_vendor_replacement',
                'result_status' => 'deferred',
                'package_id' => $package->package_id,
                'vendor_strategy' => $vendorStrategy,
                'user_facing_message' => (string) __('dberp.system_update.file_execution.log.vendor_composer_deferred'),
                'deferred' => $summary['deferred'] ?? true,
            ],
        ), $execution);
    }

    public function logSystemUpdateVendorReplacementFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        string $vendorStrategy,
        HostSystemUpdateFileExecutionException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VENDOR_REPLACEMENT_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_vendor_replacement',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'vendor_strategy' => $vendorStrategy,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    /**
     * @param  list<string>  $declaredMigrationPaths
     */
    public function logSystemUpdateMigrationStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        int $declaredMigrationCount,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MIGRATION_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_migration',
                'result_status' => 'started',
                'package_id' => $package->package_id,
                'declared_migration_count' => $declaredMigrationCount,
            ],
        ), $execution);
    }

    public function logSystemUpdateMigrationCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdateArtisanCommandResult $result,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MIGRATION_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_migration',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'command' => $result->command,
                'exit_code' => $result->exitCode,
                'duration_ms' => $result->durationMs,
            ],
        ), $execution);
    }

    public function logSystemUpdateMigrationFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdatePostApplyException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MIGRATION_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_migration',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateCacheClearStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_CACHE_CLEAR_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_cache_clear',
                'result_status' => 'started',
                'package_id' => $package->package_id,
            ],
        ), $execution);
    }

    /**
     * @param  list<HostSystemUpdateArtisanCommandResult>  $results
     */
    public function logSystemUpdateCacheClearCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        array $results,
    ): void {
        $durationMs = array_sum(array_map(
            static fn (HostSystemUpdateArtisanCommandResult $result): int => $result->durationMs,
            $results,
        ));

        $this->log(self::ACTION_SYSTEM_UPDATE_CACHE_CLEAR_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_cache_clear',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'command_count' => count($results),
                'duration_ms' => $durationMs,
            ],
        ), $execution);
    }

    public function logSystemUpdateCacheClearFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdatePostApplyException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_CACHE_CLEAR_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_cache_clear',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateVersionWriteStarted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        string $fromDisplayVersion,
        int $fromUpdateVersion,
        string $toDisplayVersion,
        int $toUpdateVersion,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VERSION_WRITE_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_version_write',
                'result_status' => 'started',
                'package_id' => $package->package_id,
                'from_version' => $fromDisplayVersion,
                'to_version' => $toDisplayVersion,
                'from_update_version' => $fromUpdateVersion,
                'to_update_version' => $toUpdateVersion,
            ],
        ), $execution);
    }

    /**
     * @param  array{display_version: string, update_version: int, previous_display_version: string, previous_update_version: int}  $summary
     */
    public function logSystemUpdateVersionWriteCompleted(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VERSION_WRITE_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_version_write',
                'result_status' => 'success',
                'package_id' => $package->package_id,
                'from_version' => $summary['previous_display_version'] ?? null,
                'to_version' => $summary['display_version'] ?? null,
                'from_update_version' => $summary['previous_update_version'] ?? null,
                'to_update_version' => $summary['update_version'] ?? null,
            ],
        ), $execution);
    }

    public function logSystemUpdateVersionWriteFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdatePackage $package,
        HostSystemUpdatePostApplyException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_VERSION_WRITE_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_version_write',
                'result_status' => 'failed',
                'package_id' => $package->package_id,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateFailureCaptured(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateFailureContext $context,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_FAILURE_CAPTURED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_failure',
                'result_status' => 'captured',
                'failed_step' => $context->failedStep,
                'error_code' => $context->errorCode,
                'user_facing_message' => $context->userFacingMessage,
                'requires_rollback' => $context->requiresRollback,
                'command_exit_code' => $context->commandExitCode,
            ],
        ), $execution);
    }

    public function logSystemUpdateRollbackStarted(
        HostSystemUpdateExecution $execution,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_STARTED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback',
                'result_status' => 'started',
                'rollback_status' => $execution->rollback_status,
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public function logSystemUpdateRollbackFileRestoreCompleted(
        HostSystemUpdateExecution $execution,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_FILE_RESTORE_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback_file_restore',
                'result_status' => 'success',
                'restored_count' => $summary['restored_count'] ?? 0,
                'skipped_count' => $summary['skipped_count'] ?? 0,
                'missing_count' => $summary['missing_count'] ?? 0,
                'failed_count' => $summary['failed_count'] ?? 0,
            ],
        ), $execution);
    }

    public function logSystemUpdateRollbackFileRestoreFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateRecoveryException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_FILE_RESTORE_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback_file_restore',
                'result_status' => 'failed',
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $summary
     */
    public function logSystemUpdateRollbackEnvRestoreCompleted(
        HostSystemUpdateExecution $execution,
        array $summary,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_ENV_RESTORE_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback_env_restore',
                'result_status' => 'success',
                'from_version' => $summary['display_version'] ?? null,
                'to_version' => $execution->to_version,
                'from_update_version' => $summary['update_version'] ?? null,
                'env_snapshot_restored' => $summary['env_snapshot_restored'] ?? false,
            ],
        ), $execution);
    }

    public function logSystemUpdateRollbackEnvRestoreFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateRecoveryException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_ENV_RESTORE_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback_env_restore',
                'result_status' => 'failed',
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateMaintenanceModeRestored(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateArtisanCommandResult $result,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MAINTENANCE_MODE_RESTORED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_maintenance',
                'result_status' => 'success',
                'command' => $result->command,
                'exit_code' => $result->exitCode,
                'duration_ms' => $result->durationMs,
            ],
        ), $execution);
    }

    public function logSystemUpdateMaintenanceModeRestoreFailed(
        HostSystemUpdateExecution $execution,
        ?HostSystemUpdateArtisanCommandResult $result = null,
        ?string $errorCode = null,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_MAINTENANCE_MODE_RESTORE_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_maintenance',
                'result_status' => 'failed',
                'command' => $result?->command ?? 'up',
                'exit_code' => $result?->exitCode,
                'error_code' => $errorCode ?? 'recovery_maintenance_up_failed',
            ],
        ), $execution);
    }

    public function logSystemUpdateRollbackCompleted(
        HostSystemUpdateExecution $execution,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback',
                'result_status' => 'completed',
                'rollback_status' => $execution->rollback_status,
            ],
        ), $execution);
    }

    public function logSystemUpdateRollbackFailed(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateRecoveryException $exception,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_ROLLBACK_FAILED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_rollback',
                'result_status' => 'failed',
                'rollback_status' => $execution->rollback_status,
                'error_code' => $exception->errorCode(),
                'user_facing_message' => $exception->userFacingMessage(),
            ],
        ), $execution);
    }

    public function logSystemUpdateExecutionCompleted(
        HostSystemUpdateExecution $execution,
    ): void {
        $this->log(self::ACTION_SYSTEM_UPDATE_EXECUTION_COMPLETED, array_merge(
            $this->executionAuditPayload($execution),
            [
                'operation' => 'host_system_update_execution',
                'result_status' => 'completed',
                'status' => $execution->status,
            ],
        ), $execution);
    }

    /**
     * @param  array<string, mixed>  $extra
     * @return array<string, mixed>
     */
    private function executionAuditPayload(HostSystemUpdateExecution $execution, array $extra = []): array
    {
        return array_merge([
            'execution_no' => $execution->execution_no,
            'package_id' => $execution->package_id,
            'from_version' => $execution->from_version,
            'to_version' => $execution->to_version,
            'from_update_version' => $execution->from_update_version,
            'to_update_version' => $execution->to_update_version,
            'status' => $execution->status,
            'current_step' => $execution->current_step,
            'operator_id' => $execution->operator_id,
            'operator_name' => $execution->operator_name,
        ], $extra);
    }

    public static function maskIdentifier(string $value): string
    {
        $trimmed = trim($value);
        $length = strlen($trimmed);

        if ($length === 0) {
            return '';
        }

        if ($length <= 4) {
            return str_repeat('*', $length);
        }

        return substr($trimmed, 0, 2)
            .str_repeat('*', max(1, $length - 4))
            .substr($trimmed, -2);
    }

    /**
     * @param  array<string, mixed>  $extra
     */
    private function logFailure(
        string $action,
        string $operation,
        SupportCenterException $exception,
        array $extra = [],
        ?Model $auditable = null,
    ): void {
        if ($this->isConnectivityError($exception->errorCode())) {
            $this->logConnectivityBlocked($operation, $exception);
        }

        $this->log($action, array_merge($extra, [
            'operation' => $operation,
            'result_status' => 'failed',
            'error_code' => $exception->errorCode(),
            'user_facing_message' => $exception->userFacingMessage(),
            'request_id' => $exception->requestId(),
        ]), $auditable);
    }

    /**
     * @param  array<string, mixed>  $context
     */
    private function log(string $action, array $context, ?Model $auditable = null): void
    {
        $operator = Auth::user();

        $payload = array_merge([
            'product_code' => (string) config('dberp.support_center.product_code', 'dberp'),
            'occurred_at' => now()->utc()->toIso8601String(),
            'operator_id' => $operator instanceof Authenticatable ? $operator->getAuthIdentifier() : null,
            'operator_name' => $this->operatorName($operator),
        ], $context);

        $this->auditService->log(
            $action,
            $auditable,
            null,
            SupportCenterSnapshotSanitizer::sanitize($payload),
        );
    }

    private function operatorName(?Authenticatable $operator): ?string
    {
        if ($operator === null) {
            return null;
        }

        if (method_exists($operator, 'getAttribute')) {
            $name = $operator->getAttribute('name');

            if (is_string($name) && trim($name) !== '') {
                return trim($name);
            }
        }

        return null;
    }

    private function nullableString(mixed $value): ?string
    {
        if (! is_string($value)) {
            return null;
        }

        $trimmed = trim($value);

        return $trimmed === '' ? null : $trimmed;
    }

    private function isConnectivityError(?string $errorCode): bool
    {
        return in_array($errorCode, [
            SupportCenterUserFacingErrors::SUPPORT_CENTER_DISABLED,
            SupportCenterUserFacingErrors::STUB_MODE_ENABLED,
            SupportCenterUserFacingErrors::BASE_URL_NOT_CONFIGURED,
            SupportCenterUserFacingErrors::HOST_TOKEN_NOT_CONFIGURED,
        ], true);
    }
}
