<?php

declare(strict_types=1);

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

namespace App\Services\SupportCenter;

use App\Exceptions\SupportCenter\SupportCenterException;
use InvalidArgumentException;

/**
 * 接入码确认（Support Center task_no / access code）。
 */
final class HostSiteOnboardingConfirmService
{
    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 confirm(string $accessCode): array
    {
        $taskNo = trim($accessCode);

        if ($taskNo === '') {
            throw new InvalidArgumentException((string) __('dberp.site_onboarding.errors.access_code_required'));
        }

        $payload = $this->compactPayload($this->contextBuilder->siteOnboardingConfirmBody($taskNo));

        try {
            $responseData = $this->transport->post(
                SupportCenterOpenHostEndpoints::SITE_BINDING_ACCESS_CONFIRM,
                $payload,
                'site_onboarding_confirm',
            );

            $normalized = $this->normalizeFromResponse($responseData, $taskNo);

            $this->lastAttemptStore->store([
                'attempted_at' => now()->utc()->toIso8601String(),
                'task_no' => $taskNo,
                'success' => true,
                'response' => $responseData,
            ]);

            $this->statusCacheStore->store($normalized);
            $this->siteVerificationStaticPublisher->publish();

            $this->auditLogger->logSiteAccessConfirmSucceeded($normalized, $taskNo);

            return $normalized;
        } catch (SupportCenterException $exception) {
            $this->lastAttemptStore->store([
                'attempted_at' => now()->utc()->toIso8601String(),
                'task_no' => $taskNo,
                'success' => false,
                'error_code' => $exception->errorCode(),
                'message' => $exception->userFacingMessage(),
                'request_id' => $exception->requestId(),
            ]);

            $this->auditLogger->logSiteAccessConfirmFailed($taskNo, $exception);

            throw $exception;
        }
    }

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

        return [
            'fetched_at' => now()->utc()->toIso8601String(),
            'task_no' => $this->statusPresenter->extractTaskNo($payload) ?? $taskNo,
            'site_no' => $this->statusPresenter->extractSiteNo($payload),
            '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,
        ];
    }

    /**
     * access-confirm 可能附带 status_snapshot 子对象，优先合并顶层 Open Host 字段。
     *
     * @param  array<string, mixed>  $responseData
     * @return array<string, mixed>
     */
    private function unwrapStatusPayload(array $responseData): array
    {
        $nested = $responseData['status_snapshot'] ?? null;

        if (! is_array($nested)) {
            return $responseData;
        }

        return array_merge($nested, array_filter(
            $responseData,
            static fn (mixed $value, string $key): bool => $key !== 'status_snapshot' && $value !== null && $value !== '',
            ARRAY_FILTER_USE_BOTH,
        ));
    }

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>
     */
    private function compactPayload(array $payload): array
    {
        return array_filter(
            $payload,
            static fn (mixed $value): bool => $value !== null && $value !== '',
        );
    }
}
