<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use App\Models\HostSystemUpdatePackage;

/**
 * 整包级校验和验证（不解析 manifest.json）。
 */
final class HostSystemUpdatePackageVerifier
{
    public const DEFAULT_ALGORITHM = 'sha256';

    public function verify(HostSystemUpdatePackage $package): HostSystemUpdatePackage
    {
        $path = $package->local_path;

        if (! is_string($path) || $path === '' || ! is_file($path)) {
            return $this->markVerificationFailed(
                $package,
                (string) __('dberp.system_update.package.verification_file_missing'),
                'verification_file_missing',
            );
        }

        $expectedChecksum = $this->normalizeChecksum($package->checksum);

        if ($expectedChecksum === null) {
            return $this->markVerificationFailed(
                $package,
                (string) __('dberp.system_update.package.verification_checksum_missing'),
                'verification_checksum_missing',
            );
        }

        $algorithm = $this->resolveAlgorithm($package->checksum_algorithm);
        $computed = $this->computeFileChecksum($path, $algorithm);

        if ($computed === null) {
            return $this->markVerificationFailed(
                $package,
                (string) __('dberp.system_update.package.verification_compute_failed'),
                'verification_compute_failed',
            );
        }

        if (! hash_equals($expectedChecksum, $computed)) {
            return $this->markVerificationFailed(
                $package,
                (string) __('dberp.system_update.package.verification_checksum_mismatch'),
                'verification_checksum_mismatch',
            );
        }

        $package->fill([
            'verified' => true,
            'verified_at' => now()->utc(),
            'download_status' => HostSystemUpdatePackage::STATUS_VERIFIED,
            'download_message' => null,
            'download_error_code' => null,
        ]);
        $package->save();

        return $package->fresh() ?? $package;
    }

    public function resolveAlgorithm(?string $configuredAlgorithm): string
    {
        $algorithm = strtolower(trim((string) $configuredAlgorithm));

        if ($algorithm === '') {
            return self::DEFAULT_ALGORITHM;
        }

        if (! in_array($algorithm, hash_algos(), true)) {
            return self::DEFAULT_ALGORITHM;
        }

        return $algorithm;
    }

    public function normalizeChecksum(?string $checksum): ?string
    {
        if ($checksum === null) {
            return null;
        }

        $trimmed = strtolower(trim($checksum));

        if ($trimmed === '') {
            return null;
        }

        if (str_contains($trimmed, ':')) {
            [, $value] = array_pad(explode(':', $trimmed, 2), 2, null);
            $trimmed = strtolower(trim((string) $value));
        }

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

    private function computeFileChecksum(string $path, string $algorithm): ?string
    {
        $hash = @hash_file($algorithm, $path);

        return is_string($hash) && $hash !== '' ? strtolower($hash) : null;
    }

    private function markVerificationFailed(
        HostSystemUpdatePackage $package,
        string $message,
        string $errorCode,
    ): HostSystemUpdatePackage {
        $package->fill([
            'verified' => false,
            'verified_at' => null,
            'download_status' => HostSystemUpdatePackage::STATUS_VERIFICATION_FAILED,
            'download_message' => $message,
            'download_error_code' => $errorCode,
        ]);
        $package->save();

        return $package->fresh() ?? $package;
    }
}
