<?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\CorePlugin;
use App\Services\DberpPermissionService;
use App\Support\DberpProductVersion;
use DBCore\Plugin\Enums\PluginStatus;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Schema;
use Throwable;

/**
 * 结合本地安装状态、RBAC 与官方权益，解析目录条目 UI 状态。
 */
final class HostPluginCatalogInstallStateResolver
{
    public function __construct(
        private readonly HostPluginAvailabilityPresenter $availabilityPresenter,
        private readonly HostPluginEntitlementGate $entitlementGate,
        private readonly DberpPermissionService $permissionService,
        private readonly DberpProductVersion $productVersion,
    ) {}

    /**
     * @return array{
     *     state: string,
     *     state_label: string,
     *     state_color: string,
     *     show_install_action: bool,
     *     install_blocked_reason: ?string,
     *     installed_version: ?string
     * }
     */
    public function resolve(HostPluginCatalogItem $item, ?Authenticatable $user): array
    {
        $installed = $this->findInstalledRecord($item->pluginCode);
        $installedVersion = $installed?->version !== null ? (string) $installed->version : null;
        $remoteAvailability = strtolower(trim($item->availability));

        if ($installed !== null && $this->isActiveInstallation((string) $installed->status)) {
            if ($this->hasNewerVersion($installedVersion, $item->latestVersion)) {
                return $this->buildState(
                    state: HostPluginAvailabilityPresenter::STATE_UPDATE_AVAILABLE,
                    showInstall: $this->canShowUpdateAction($user),
                    blockedReason: $this->updateBlockedReason($user),
                    installedVersion: $installedVersion,
                );
            }

            return $this->buildState(
                state: HostPluginAvailabilityPresenter::STATE_INSTALLED,
                showInstall: false,
                blockedReason: null,
                installedVersion: $installedVersion,
            );
        }

        if (in_array($remoteAvailability, ['unavailable', 'deprecated', 'maintenance', 'disabled'], true)) {
            return $this->buildState(
                state: HostPluginAvailabilityPresenter::STATE_UNAVAILABLE,
                showInstall: false,
                blockedReason: $this->availabilityPresenter->reasonCodeLabel($item->remoteReasonCode)
                    ?? $this->availabilityPresenter->remoteAvailabilityLabel($item->availability),
                installedVersion: $installedVersion,
            );
        }

        if ($remoteAvailability === 'viewable') {
            $isVersionIncompatible = $this->availabilityPresenter->isVersionIncompatibilityReason($item->remoteReasonCode)
                || $this->isLocallyVersionIncompatible($item);

            if ($isVersionIncompatible) {
                return $this->buildState(
                    state: HostPluginAvailabilityPresenter::STATE_INCOMPATIBLE_VERSION,
                    showInstall: false,
                    blockedReason: $this->availabilityPresenter->blockedReasonLabel(
                        $item->remoteReasonCode,
                        'dberp.plugin_center.catalog.reason.incompatible_version',
                    ),
                    installedVersion: $installedVersion,
                );
            }

            return $this->buildState(
                state: HostPluginAvailabilityPresenter::STATE_LICENSE_REQUIRED,
                showInstall: false,
                blockedReason: $this->availabilityPresenter->blockedReasonLabel(
                    $item->remoteReasonCode,
                    'dberp.plugin_center.catalog.requires_commercial_license',
                ),
                installedVersion: $installedVersion,
            );
        }

        if (in_array($remoteAvailability, ['license_required', 'commercial_required'], true)
            || $this->requiresCommercialLicense($item)) {
            return $this->buildState(
                state: HostPluginAvailabilityPresenter::STATE_LICENSE_REQUIRED,
                showInstall: false,
                blockedReason: (string) __('dberp.plugin_center.catalog.requires_commercial_license'),
                installedVersion: $installedVersion,
            );
        }

        return $this->buildState(
            state: HostPluginAvailabilityPresenter::STATE_INSTALLABLE,
            showInstall: $this->canShowInstallAction($user),
            blockedReason: $this->installBlockedReason($user),
            installedVersion: $installedVersion,
        );
    }

    /**
     * @return array{
     *     state: string,
     *     state_label: string,
     *     state_color: string,
     *     show_install_action: bool,
     *     install_blocked_reason: ?string,
     *     installed_version: ?string
     * }
     */
    private function buildState(
        string $state,
        bool $showInstall,
        ?string $blockedReason,
        ?string $installedVersion,
    ): array {
        return [
            'state' => $state,
            'state_label' => $this->availabilityPresenter->labelForState($state),
            'state_color' => $this->availabilityPresenter->badgeColorForState($state),
            'show_install_action' => $showInstall,
            'install_blocked_reason' => $blockedReason,
            'installed_version' => $installedVersion,
        ];
    }

    private function canShowInstallAction(?Authenticatable $user): bool
    {
        if ($user === null) {
            return false;
        }

        if (! $this->permissionService->allows($user, DberpPermissionService::INSTALL_HOST_PLUGIN)) {
            return false;
        }

        return $this->entitlementGate->canInstallPlugin();
    }

    private function canShowUpdateAction(?Authenticatable $user): bool
    {
        if ($user === null) {
            return false;
        }

        if (! $this->permissionService->allows($user, DberpPermissionService::UPDATE_HOST_PLUGIN)) {
            return false;
        }

        return $this->entitlementGate->canUpdatePlugin();
    }

    private function installBlockedReason(?Authenticatable $user): ?string
    {
        if ($user === null || ! $this->permissionService->allows($user, DberpPermissionService::INSTALL_HOST_PLUGIN)) {
            return (string) __('dberp.plugin_center.install.permission_denied');
        }

        if (! $this->entitlementGate->canInstallPlugin()) {
            return $this->entitlementGate->installReason();
        }

        return null;
    }

    private function updateBlockedReason(?Authenticatable $user): ?string
    {
        if ($user === null || ! $this->permissionService->allows($user, DberpPermissionService::UPDATE_HOST_PLUGIN)) {
            return (string) __('dberp.plugin_center.install.update_permission_denied');
        }

        if (! $this->entitlementGate->canUpdatePlugin()) {
            return $this->entitlementGate->updateReason();
        }

        return null;
    }

    private function requiresCommercialLicense(HostPluginCatalogItem $item): bool
    {
        $license = strtolower(trim((string) ($item->requiredLicense ?? '')));

        return in_array($license, ['commercial', 'paid', 'license'], true);
    }

    private function isLocallyVersionIncompatible(HostPluginCatalogItem $item): bool
    {
        if ($item->compatibleDberpVersions === []) {
            return false;
        }

        $hostVersion = $this->productVersion->displayVersion();

        foreach ($item->compatibleDberpVersions as $requiredVersion) {
            if (version_compare($hostVersion, $requiredVersion, '<')) {
                return true;
            }
        }

        return false;
    }

    private function hasNewerVersion(?string $installedVersion, ?string $latestVersion): bool
    {
        if ($installedVersion === null || $latestVersion === null) {
            return false;
        }

        return version_compare($latestVersion, $installedVersion, '>');
    }

    private function isActiveInstallation(string $status): bool
    {
        return in_array($status, [
            PluginStatus::Installed->value,
            PluginStatus::Enabled->value,
            PluginStatus::Disabled->value,
        ], true);
    }

    private function findInstalledRecord(string $pluginCode): ?CorePlugin
    {
        if (! $this->pluginTableReady()) {
            return null;
        }

        return CorePlugin::query()
            ->where('identifier', $pluginCode)
            ->first();
    }

    private function pluginTableReady(): bool
    {
        try {
            return Schema::hasTable('core_plugins');
        } catch (Throwable) {
            return false;
        }
    }
}
