<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use App\Exceptions\SupportCenter\SupportCenterException;

/**
 * 查询远程站点绑定状态并缓存快照。
 */
final class HostSiteOnboardingStatusQueryService
{
    public function __construct(
        private readonly SupportCenterOpenApiTransport $transport,
        private readonly SupportCenterRequestContextBuilder $contextBuilder,
        private readonly HostSiteOnboardingLastAttemptStore $lastAttemptStore,
        private readonly HostSiteOnboardingStatusCacheStore $statusCacheStore,
        private readonly HostSiteOnboardingStatusPresenter $statusPresenter,
        private readonly HostSiteVerificationStaticPublisher $siteVerificationStaticPublisher,
        private readonly SupportCenterAuditLogger $auditLogger,
    ) {}

    /**
     * @return array<string, mixed>
     */
    public function refresh(?string $taskNo = null): array
    {
        $taskNo = $this->resolveTaskNo($taskNo);
        $query = $this->buildStatusQuery($taskNo);

        try {
            $responseData = $this->transport->get(
                SupportCenterOpenHostEndpoints::SITE_BINDING_STATUS,
                $query,
                'site_onboarding_status',
            );

            $normalized = $this->normalizeFromResponse($responseData, $taskNo);
            $this->statusCacheStore->store($normalized);
            $this->siteVerificationStaticPublisher->publish();

            $this->auditLogger->logSiteBindingStatusRefreshed($normalized);

            return $normalized;
        } catch (SupportCenterException $exception) {
            $this->auditLogger->logSiteBindingStatusRefreshFailed($exception);

            throw $exception;
        }
    }

    /**
     * @return array<string, mixed>|null
     */
    public function cachedStatus(): ?array
    {
        return $this->statusCacheStore->get();
    }

    private function resolveTaskNo(?string $taskNo): ?string
    {
        $trimmed = is_string($taskNo) ? trim($taskNo) : '';

        if ($trimmed !== '') {
            return $trimmed;
        }

        return $this->lastAttemptStore->latestTaskNo();
    }

    /**
     * @return array<string, mixed>
     */
    private function buildStatusQuery(?string $taskNo): array
    {
        $context = $this->contextBuilder->siteOnboardingStatusQuery($taskNo);

        $allowedKeys = ['product_code', 'product', 'instance_id', 'task_no'];

        return array_filter(
            array_intersect_key($context, array_flip($allowedKeys)),
            static fn (mixed $value): bool => $value !== null && $value !== '',
        );
    }

    /**
     * @param  array<string, mixed>  $responseData
     * @return array<string, mixed>
     */
    private function normalizeFromResponse(array $responseData, ?string $fallbackTaskNo): array
    {
        $snapshot = $this->statusPresenter->normalizeFromOpenHostData($responseData);

        return [
            'fetched_at' => now()->utc()->toIso8601String(),
            'task_no' => $this->statusPresenter->extractTaskNo($responseData) ?? $fallbackTaskNo,
            'site_no' => $this->statusPresenter->extractSiteNo($responseData),
            'binding_status' => $snapshot['binding_status'],
            'binding_status_label' => $snapshot['binding_status_label'],
            'is_bound' => $snapshot['is_bound'],
            'next_action' => $snapshot['next_action'],
            'next_action_hint' => $snapshot['next_action_hint'],
            'data' => $responseData,
        ];
    }
}
