<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use App\Enums\SupportCenter\HostInstanceIdentityStatus;
use DBCore\Setting\Contracts\SettingManagerInterface;
use Illuminate\Support\Str;

/**
 * 自动生成并持久化站点实例身份（instance_id + 本地 signing_secret），供后续官方接入绑定准备。
 */
final class HostInstanceIdentityService
{
    public function __construct(
        private readonly SettingManagerInterface $settingManager,
        private readonly HostInstanceCredentialStore $credentialStore,
        private readonly HostSiteOnboardingStatusCacheStore $onboardingStatusCacheStore,
        private readonly HostSiteOnboardingStatusPresenter $onboardingStatusPresenter,
    ) {}

    /**
     * 幂等：确保 instance_id 与 signing_secret 均已生成并持久化。
     */
    public function ensureProvisioned(): void
    {
        $this->resolveInstanceId();
        $this->ensureSigningSecret();
    }

    public function instanceId(): string
    {
        return $this->resolveInstanceId();
    }

    public function identityStatus(): HostInstanceIdentityStatus
    {
        $this->ensureProvisioned();

        if ($this->isOfficialAccessBound()) {
            return HostInstanceIdentityStatus::OfficialAccessBound;
        }

        return HostInstanceIdentityStatus::Provisioned;
    }

    public function isProvisioned(): bool
    {
        return $this->readStoredInstanceId() !== null && $this->credentialStore->hasSigningSecret();
    }

    private function isOfficialAccessBound(): bool
    {
        $cached = $this->onboardingStatusCacheStore->get();

        if (is_array($cached) && array_key_exists('is_bound', $cached)) {
            return (bool) $cached['is_bound'];
        }

        if (! is_array($cached)) {
            return false;
        }

        if ($this->onboardingStatusPresenter->resolveIsBoundFromData($cached)) {
            return true;
        }

        $data = $cached['data'] ?? null;

        return is_array($data) && $this->onboardingStatusPresenter->resolveIsBoundFromData($data);
    }

    private function resolveInstanceId(): string
    {
        $stored = $this->readStoredInstanceId();

        if ($stored !== null) {
            return $stored;
        }

        $identity = (string) Str::uuid();

        $this->persistInstanceId($identity);

        return $identity;
    }

    private function ensureSigningSecret(): void
    {
        if ($this->credentialStore->hasSigningSecret()) {
            return;
        }

        $this->credentialStore->storeSigningSecret($this->generateSigningSecret());
    }

    private function generateSigningSecret(): string
    {
        return Str::random(64);
    }

    private function readStoredInstanceId(): ?string
    {
        $fromSettings = $this->readInstanceIdFromSettings();

        if ($fromSettings !== null) {
            return $fromSettings;
        }

        return $this->readInstanceIdFromFallbackFile();
    }

    private function readInstanceIdFromSettings(): ?string
    {
        try {
            $value = $this->settingManager->get(HostInstallationIdentityService::SETTING_KEY);
        } catch (\Throwable) {
            return $this->readInstanceIdFromFallbackFile();
        }

        if (! is_string($value) || trim($value) === '') {
            return null;
        }

        return trim($value);
    }

    private function persistInstanceId(string $identity): void
    {
        try {
            $result = $this->settingManager->set(HostInstallationIdentityService::SETTING_KEY, $identity);

            if ($result->isSuccess()) {
                return;
            }
        } catch (\Throwable) {
            // DBCore Setting 不可用时回退到本地文件，避免 well-known 每次请求生成新 ID。
        }

        $this->writeInstanceIdFallbackFile($identity);
    }

    private function instanceIdFallbackFilePath(): string
    {
        return storage_path('app/dberp/host-installation-site-identity');
    }

    private function readInstanceIdFromFallbackFile(): ?string
    {
        $path = $this->instanceIdFallbackFilePath();

        if (! is_file($path)) {
            return null;
        }

        $contents = trim((string) @file_get_contents($path));

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

    private function writeInstanceIdFallbackFile(string $identity): void
    {
        $directory = dirname($this->instanceIdFallbackFilePath());

        if (! is_dir($directory)) {
            @mkdir($directory, 0755, true);
        }

        @file_put_contents($this->instanceIdFallbackFilePath(), $identity, LOCK_EX);
    }
}
