<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

/**
 * API 서버 토큰 교환 서비스
 *
 * MNG → API 서버간 HMAC 인증을 통해 Bearer 토큰을 발급받습니다.
 */
class ApiTokenService
{
    /**
     * 서명 유효 시간 (초) - API 서버와 동일하게 5분
     */
    private const SIGNATURE_VALID_DURATION = 300;

    /**
     * API 토큰 교환
     *
     * @param  int  $userId  사용자 ID
     * @param  int  $tenantId  테넌트 ID
     * @return array{success: bool, data?: array, error?: string}
     */
    public function exchangeToken(int $userId, int $tenantId): array
    {
        $baseUrl = config('services.api.base_url');
        $exchangeSecret = config('services.api.exchange_secret');

        if (empty($baseUrl)) {
            Log::error('[ApiTokenService] API base URL not configured');

            return ['success' => false, 'error' => 'API 서버 URL이 설정되지 않았습니다.'];
        }

        if (empty($exchangeSecret)) {
            Log::error('[ApiTokenService] Exchange secret not configured');

            return ['success' => false, 'error' => '토큰 교환 비밀키가 설정되지 않았습니다.'];
        }

        // 만료 시간 계산 (현재 시간 + 유효 시간)
        $exp = time() + self::SIGNATURE_VALID_DURATION;

        // HMAC 서명 생성
        $payload = "{$userId}:{$tenantId}:{$exp}";
        $signature = hash_hmac('sha256', $payload, $exchangeSecret);

        try {
            $response = Http::timeout(10)
                ->post("{$baseUrl}/api/v1/internal/exchange-token", [
                    'user_id' => $userId,
                    'tenant_id' => $tenantId,
                    'exp' => $exp,
                    'signature' => $signature,
                ]);

            if ($response->successful()) {
                $data = $response->json('data');
                Log::info('[ApiTokenService] Token exchanged successfully', [
                    'user_id' => $userId,
                    'tenant_id' => $tenantId,
                ]);

                return [
                    'success' => true,
                    'data' => [
                        'access_token' => $data['access_token'],
                        'token_type' => $data['token_type'] ?? 'Bearer',
                        'expires_in' => $data['expires_in'] ?? 3600,
                    ],
                ];
            }

            $error = $response->json('message') ?? '토큰 교환에 실패했습니다.';
            Log::warning('[ApiTokenService] Token exchange failed', [
                'user_id' => $userId,
                'tenant_id' => $tenantId,
                'status' => $response->status(),
                'error' => $error,
            ]);

            return ['success' => false, 'error' => $error];
        } catch (\Exception $e) {
            Log::error('[ApiTokenService] Token exchange exception', [
                'user_id' => $userId,
                'tenant_id' => $tenantId,
                'exception' => $e->getMessage(),
            ]);

            return ['success' => false, 'error' => 'API 서버 연결에 실패했습니다.'];
        }
    }

    /**
     * 세션에 저장된 API 토큰 조회
     */
    public function getSessionToken(): ?string
    {
        return session('api_access_token');
    }

    /**
     * API 토큰을 세션에 저장
     *
     * @param  string  $token  Bearer 토큰
     * @param  int  $expiresIn  만료 시간 (초)
     */
    public function storeTokenInSession(string $token, int $expiresIn): void
    {
        session([
            'api_access_token' => $token,
            'api_token_expires_at' => now()->addSeconds($expiresIn)->timestamp,
        ]);
    }

    /**
     * 세션의 API 토큰 삭제
     */
    public function clearSessionToken(): void
    {
        session()->forget(['api_access_token', 'api_token_expires_at']);
    }

    /**
     * 토큰이 만료되었는지 확인
     */
    public function isTokenExpired(): bool
    {
        $expiresAt = session('api_token_expires_at');

        if (! $expiresAt) {
            return true;
        }

        // 5분 전에 미리 갱신하도록 (버퍼)
        return time() > ($expiresAt - 300);
    }
}
