<?php

namespace App\Services\FlowTester;

use Exception;
use Illuminate\Support\Facades\Http;

/**
 * HTTP 클라이언트 래퍼
 *
 * Laravel HTTP Client를 래핑하여 플로우 테스터에 맞게 제공합니다.
 */
class HttpClient
{
    private string $baseUrl = '';

    private int $timeout = 30;

    private array $defaultHeaders = [];

    private ?string $apiKey = null;

    private ?string $bearerToken = null;

    private bool $verifySsl = true;

    private ?string $hostHeader = null;

    /**
     * SSL 검증 비활성화 (Docker 내부 통신용)
     */
    public function withoutVerifying(): self
    {
        $this->verifySsl = false;

        return $this;
    }

    /**
     * Host 헤더 설정 (Docker 내부 통신용)
     */
    public function setHostHeader(string $host): self
    {
        $this->hostHeader = $host;

        return $this;
    }

    /**
     * 기본 URL 설정
     */
    public function setBaseUrl(string $url): self
    {
        $this->baseUrl = rtrim($url, '/');

        return $this;
    }

    /**
     * 타임아웃 설정 (초)
     */
    public function setTimeout(int $seconds): self
    {
        $this->timeout = $seconds;

        return $this;
    }

    /**
     * 기본 헤더 설정
     */
    public function setDefaultHeaders(array $headers): self
    {
        $this->defaultHeaders = $headers;

        return $this;
    }

    /**
     * API 키 설정 (X-API-KEY 헤더)
     */
    public function setApiKey(string $apiKey): self
    {
        $this->apiKey = $apiKey;

        return $this;
    }

    /**
     * Bearer 토큰 설정
     */
    public function setBearerToken(string $token): self
    {
        $this->bearerToken = $token;

        return $this;
    }

    /**
     * HTTP 요청 실행
     *
     * @param  string  $method  HTTP 메서드
     * @param  string  $endpoint  엔드포인트
     * @param  array  $options  옵션 ['headers' => [], 'body' => [], 'query' => []]
     * @return array ['status' => int, 'headers' => array, 'body' => array, 'duration' => int]
     */
    public function request(string $method, string $endpoint, array $options = []): array
    {
        $startTime = microtime(true);

        $url = $this->buildUrl($endpoint);
        $headers = $this->buildHeaders($options['headers'] ?? []);

        try {
            $request = Http::timeout($this->timeout)
                ->withHeaders($headers);

            // SSL 검증 비활성화 (Docker 내부 통신용)
            if (! $this->verifySsl) {
                $request = $request->withoutVerifying();
            }

            // Host 헤더 추가 (Docker 내부 통신용)
            if ($this->hostHeader) {
                $request = $request->withHeaders(['Host' => $this->hostHeader]);
            }

            // API 키 추가
            if ($this->apiKey) {
                $request = $request->withHeaders(['X-API-KEY' => $this->apiKey]);
            }

            // Bearer 토큰 추가 (스텝 헤더에 Authorization이 없는 경우에만)
            if ($this->bearerToken && ! isset($headers['Authorization'])) {
                $request = $request->withToken($this->bearerToken);
            }

            // 쿼리 파라미터
            if (! empty($options['query'])) {
                $url .= '?'.http_build_query($options['query']);
            }

            // 요청 실행
            $response = match (strtoupper($method)) {
                'GET' => $request->get($url),
                'POST' => $request->post($url, $options['body'] ?? []),
                'PUT' => $request->put($url, $options['body'] ?? []),
                'PATCH' => $request->patch($url, $options['body'] ?? []),
                'DELETE' => $request->delete($url, $options['body'] ?? []),
                default => throw new Exception("Unsupported HTTP method: {$method}"),
            };

            $duration = (int) ((microtime(true) - $startTime) * 1000);

            return [
                'status' => $response->status(),
                'headers' => $response->headers(),
                'body' => $response->json() ?? [],
                'duration' => $duration,
                'success' => $response->successful(),
                'error' => null,
            ];
        } catch (Exception $e) {
            $duration = (int) ((microtime(true) - $startTime) * 1000);

            return [
                'status' => 0,
                'headers' => [],
                'body' => [],
                'duration' => $duration,
                'success' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * GET 요청
     */
    public function get(string $endpoint, array $query = [], array $headers = []): array
    {
        return $this->request('GET', $endpoint, [
            'query' => $query,
            'headers' => $headers,
        ]);
    }

    /**
     * POST 요청
     */
    public function post(string $endpoint, array $body = [], array $headers = []): array
    {
        return $this->request('POST', $endpoint, [
            'body' => $body,
            'headers' => $headers,
        ]);
    }

    /**
     * PUT 요청
     */
    public function put(string $endpoint, array $body = [], array $headers = []): array
    {
        return $this->request('PUT', $endpoint, [
            'body' => $body,
            'headers' => $headers,
        ]);
    }

    /**
     * PATCH 요청
     */
    public function patch(string $endpoint, array $body = [], array $headers = []): array
    {
        return $this->request('PATCH', $endpoint, [
            'body' => $body,
            'headers' => $headers,
        ]);
    }

    /**
     * DELETE 요청
     */
    public function delete(string $endpoint, array $body = [], array $headers = []): array
    {
        return $this->request('DELETE', $endpoint, [
            'body' => $body,
            'headers' => $headers,
        ]);
    }

    /**
     * 전체 URL 구성
     */
    private function buildUrl(string $endpoint): string
    {
        $endpoint = ltrim($endpoint, '/');

        if (empty($this->baseUrl)) {
            return $endpoint;
        }

        return $this->baseUrl.'/'.$endpoint;
    }

    /**
     * 헤더 병합
     */
    private function buildHeaders(array $additionalHeaders): array
    {
        return array_merge(
            [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            $this->defaultHeaders,
            $additionalHeaders
        );
    }
}
