<?php

declare(strict_types=1);

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

namespace App\Services\Plugin;

use App\Exceptions\SupportCenter\SupportCenterException;
use App\Services\SupportCenter\SupportCenterOpenApiTransport;
use App\Services\SupportCenter\SupportCenterOpenHostEndpoints;
use App\Services\SupportCenter\SupportCenterRequestContextBuilder;

/**
 * 安装前向 Support Center 发起 claim-check。
 */
final class HostPluginClaimCheckService
{
    public function __construct(
        private readonly SupportCenterOpenApiTransport $transport,
        private readonly SupportCenterRequestContextBuilder $contextBuilder,
        private readonly HostPluginSupportCenterContextResolver $contextResolver,
        private readonly HostPluginEntitlementGate $entitlementGate,
        private readonly HostPluginOperationLogger $operationLogger,
    ) {}

    public function assertClaimAllowed(
        string $pluginCode,
        string $version,
        HostPluginRemotePackagePurpose $purpose = HostPluginRemotePackagePurpose::Install,
    ): HostPluginClaimCheckResult {
        $this->assertEntitlementForPurpose($purpose);

        $this->operationLogger->logStarted(
            HostPluginOperationLogger::OPERATION_CLAIM_CHECK,
            $pluginCode,
            ['version' => $version],
        );

        try {
            $response = $this->transport->post(
                SupportCenterOpenHostEndpoints::pluginClaimCheck($pluginCode),
                $this->contextBuilder->pluginClaimCheckBody(
                    version: $version,
                    siteNo: $this->contextResolver->resolveSiteNo(),
                    licenseNo: $this->contextResolver->resolveLicenseNo(),
                ),
                'host_plugin_claim_check',
            );

            $allowed = filter_var(
                $response['downloadable']
                    ?? $response['allowed']
                    ?? $response['claim_allowed']
                    ?? false,
                FILTER_VALIDATE_BOOLEAN,
            );

            if (! $allowed) {
                $reasonCode = is_string($response['reason_code'] ?? null) ? (string) $response['reason_code'] : 'claim_denied';

                $this->operationLogger->logFailed(
                    HostPluginOperationLogger::OPERATION_CLAIM_CHECK,
                    $pluginCode,
                    (string) __('dberp.plugin_center.install.claim_denied'),
                    $reasonCode,
                    is_string($response['request_id'] ?? null) ? (string) $response['request_id'] : null,
                );

                throw SupportCenterException::entitlementBlocked(
                    userFacingMessage: (string) __('dberp.plugin_center.install.claim_denied'),
                    operation: 'host_plugin_claim_check',
                );
            }

            $packageMetadata = is_array($response['package'] ?? null) ? $response['package'] : $response;
            $requestId = is_string($response['request_id'] ?? null) ? trim((string) $response['request_id']) : null;

            $result = new HostPluginClaimCheckResult(
                allowed: true,
                pluginCode: $pluginCode,
                version: $version,
                packageMetadata: $packageMetadata,
                requestId: $requestId,
            );

            $this->operationLogger->logCompleted(
                HostPluginOperationLogger::OPERATION_CLAIM_CHECK,
                $pluginCode,
                null,
                ['version' => $version, 'request_id' => $requestId],
            );

            return $result;
        } catch (SupportCenterException $exception) {
            $this->operationLogger->logFailed(
                HostPluginOperationLogger::OPERATION_CLAIM_CHECK,
                $pluginCode,
                $exception->userFacingMessage(),
                $exception->errorCode(),
                $exception->requestId(),
                ['version' => $version],
            );

            throw $exception;
        }
    }

    private function assertEntitlementForPurpose(HostPluginRemotePackagePurpose $purpose): void
    {
        if ($purpose === HostPluginRemotePackagePurpose::Update) {
            if (! $this->entitlementGate->canUpdatePlugin()) {
                throw SupportCenterException::entitlementBlocked(
                    userFacingMessage: $this->entitlementGate->updateReason(),
                    operation: 'host_plugin_claim_check',
                );
            }

            return;
        }

        if (! $this->entitlementGate->canInstallPlugin()) {
            throw SupportCenterException::entitlementBlocked(
                userFacingMessage: $this->entitlementGate->installReason(),
                operation: 'host_plugin_claim_check',
            );
        }
    }
}
