<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

/**
 * Support Center 运行时配置统一入口（启用开关、Stub、产品线；连接参数经 {@see SupportCenterCredentialResolver} 解析）。
 */
final class SupportCenterRuntimeConfig
{
    /**
     * @var array<string, string>
     */
    private const ENV_KEYS = [
        'enabled' => 'DBERP_SUPPORT_CENTER_ENABLED',
        'use_stub' => 'DBERP_SUPPORT_CENTER_USE_STUB',
        'base_url' => 'DBERP_SUPPORT_CENTER_BASE_URL',
        'host_token' => 'DBERP_SUPPORT_CENTER_HOST_TOKEN',
        'host_key' => 'DBERP_SUPPORT_CENTER_HOST_KEY',
        'product_code' => 'DBERP_SUPPORT_CENTER_PRODUCT_CODE',
        'allow_env_credential_fallback' => 'DBERP_SUPPORT_CENTER_ALLOW_ENV_CREDENTIAL_FALLBACK',
    ];

    public function __construct(
        private readonly SupportCenterCredentialResolver $credentialResolver,
    ) {}

    public function enabled(): bool
    {
        return (bool) config('dberp.support_center.enabled', false);
    }

    public function useStub(): bool
    {
        return (bool) config('dberp.support_center.use_stub', true);
    }

    public function baseUrl(): ?string
    {
        return $this->credentialResolver->baseUrl();
    }

    public function hostToken(): ?string
    {
        return $this->credentialResolver->hostToken();
    }

    public function hostKey(): ?string
    {
        return $this->credentialResolver->hostKey();
    }

    public function productCode(): string
    {
        $code = config('dberp.support_center.product_code', 'dberp');

        if (! is_string($code) || trim($code) === '') {
            return 'dberp';
        }

        return trim($code);
    }

    public function hasFilledBaseUrl(): bool
    {
        return $this->credentialResolver->hasBaseUrl();
    }

    public function hasFilledHostToken(): bool
    {
        return $this->credentialResolver->hasHostToken();
    }

    public function hasFilledHostKey(): bool
    {
        return $this->hostKey() !== null;
    }

    public function normalizedBaseUrl(): ?string
    {
        return $this->credentialResolver->normalizedBaseUrl();
    }

    public function envKeyFor(string $configKey): ?string
    {
        return self::ENV_KEYS[$configKey] ?? null;
    }

    public function isEnvOverridePresent(string $configKey): bool
    {
        $envKey = $this->envKeyFor($configKey);

        if ($envKey === null) {
            return false;
        }

        if (array_key_exists($envKey, $_ENV)) {
            return true;
        }

        $fromServer = $_SERVER[$envKey] ?? null;

        if ($fromServer !== null && $fromServer !== '') {
            return true;
        }

        $getenv = getenv($envKey);

        return $getenv !== false;
    }

    /**
     * @return array<string, bool>
     */
    public function envOverridePresence(): array
    {
        $presence = [];

        foreach (array_keys(self::ENV_KEYS) as $configKey) {
            $presence[$configKey] = $this->isEnvOverridePresent($configKey);
        }

        return $presence;
    }

    /**
     * 供技术支持排查；不得直接展示给普通业务用户。
     *
     * @return array<string, mixed>
     */
    public function technicalDiagnostics(?string $blockingReasonCode = null): array
    {
        return array_merge(
            [
                'enabled' => $this->enabled(),
                'use_stub' => $this->useStub(),
                'has_base_url' => $this->hasFilledBaseUrl(),
                'has_host_token' => $this->hasFilledHostToken(),
                'has_host_key' => $this->hasFilledHostKey(),
                'product_code' => $this->productCode(),
                'config_cached' => $this->configurationIsCached(),
                'env_overrides' => $this->envOverridePresence(),
                'env_keys' => self::ENV_KEYS,
                'blocking_reason_code' => $blockingReasonCode,
                'remediation_hints' => $this->remediationHints($blockingReasonCode),
            ],
            $this->credentialResolver->technicalCredentialDiagnostics(),
        );
    }

    /**
     * @return list<string>
     */
    private function remediationHints(?string $blockingReasonCode): array
    {
        if ($blockingReasonCode === null) {
            return [];
        }

        return match ($blockingReasonCode) {
            SupportCenterUserFacingErrors::SUPPORT_CENTER_DISABLED => [
                'Set '.self::ENV_KEYS['enabled'].'=true in .env (or config/dberp.php support_center.enabled).',
                'Run php artisan config:clear after changing .env when config is cached.',
            ],
            SupportCenterUserFacingErrors::STUB_MODE_ENABLED => [
                'Set '.self::ENV_KEYS['use_stub'].'=false for real HTTP calls.',
                'Run php artisan config:clear after changing .env when config is cached.',
            ],
            SupportCenterUserFacingErrors::BASE_URL_MISSING,
            SupportCenterUserFacingErrors::BASE_URL_NOT_CONFIGURED => [
                'Ensure release credentials JSON includes base_url, or set env base_url when allow_env_credential_fallback is enabled.',
            ],
            SupportCenterUserFacingErrors::RELEASE_CREDENTIAL_MISSING => [
                'Inject official release Open Host credentials file at the configured release_credentials_path (not committed to source).',
                'Obtain an official DBErp release package from the vendor if the file is missing.',
            ],
            SupportCenterUserFacingErrors::ENV_FALLBACK_MISSING => [
                'For development/private deployment: set env host_token and base_url, or enable release credentials file.',
                'Run php artisan config:clear after changing .env when config is cached.',
            ],
            SupportCenterUserFacingErrors::HOST_TOKEN_NOT_CONFIGURED => [
                'Configure release credentials or env host_token (development only).',
            ],
            default => [],
        };
    }

    private function configurationIsCached(): bool
    {
        if (! function_exists('app')) {
            return false;
        }

        try {
            return app()->configurationIsCached();
        } catch (\Throwable) {
            return false;
        }
    }
}
