<?php

declare(strict_types=1);

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

namespace App\Services\Plugin;

use App\Models\HostPluginPackage;

/**
 * 官方插件安装包校验和验证。
 */
final class HostPluginPackageVerifier
{
    public const DEFAULT_ALGORITHM = 'sha256';

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

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

        if ($package->package_size !== null && is_file($path)) {
            $actualSize = (int) filesize($path);

            if ($actualSize !== (int) $package->package_size) {
                return $this->markVerificationFailed(
                    $package,
                    (string) __('dberp.plugin_center.package.verification_size_mismatch'),
                    'verification_size_mismatch',
                );
            }
        }

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

        if ($expectedChecksum === null) {
            return $this->markVerificationFailed(
                $package,
                (string) __('dberp.plugin_center.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.plugin_center.package.verification_compute_failed'),
                'verification_compute_failed',
            );
        }

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

        $package->fill([
            'verified' => true,
            'verified_at' => now()->utc(),
            'download_status' => HostPluginPackage::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(
        HostPluginPackage $package,
        string $message,
        string $errorCode,
    ): HostPluginPackage {
        $package->fill([
            'verified' => false,
            'verified_at' => null,
            'download_status' => HostPluginPackage::STATUS_VERIFICATION_FAILED,
            'download_message' => $message,
            'download_error_code' => $errorCode,
        ]);
        $package->save();

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