<?php
// app/services/HttpClient.php

declare(strict_types=1);

namespace ScMedia\Services;

final class HttpClient {
  public function getJson(string $url, array $headers = []): array {
    $res = $this->request('GET', $url, null, $headers);
    return $this->decodeJson($res);
  }

  public function postJson(string $url, array $payload, array $headers = []): array {
    $body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if ($body === false) {
      $body = '{}';
    }
    $headers[] = 'Content-Type: application/json';
    $res = $this->request('POST', $url, $body, $headers);
    return $this->decodeJson($res);
  }

  private function request(string $method, string $url, ?string $body, array $headers): array {
    if (!function_exists('curl_init')) {
      return ['ok' => false, 'status' => 0, 'error' => 'cURL not available', 'raw' => '', 'headers' => []];
    }
    $ch = \curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
    curl_setopt($ch, CURLOPT_TIMEOUT, 20);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    $respHeaders = [];
    \curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($ch, $header) use (&$respHeaders) {
      $len = strlen($header);
      $header = trim($header);
      if ($header === '' || strpos($header, ':') === false) return $len;
      [$name, $value] = explode(':', $header, 2);
      $respHeaders[strtolower(trim($name))] = trim($value);
      return $len;
    });
    if ($body !== null) {
      curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    }
    if (count($headers) > 0) {
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }
    $raw = \curl_exec($ch);
    $err = \curl_error($ch);
    $code = (int)\curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    \curl_close($ch);

    if ($raw === false) {
      return ['ok' => false, 'status' => $code, 'error' => $err !== '' ? $err : 'request failed', 'raw' => '', 'headers' => $respHeaders];
    }

    return ['ok' => ($code >= 200 && $code < 300), 'status' => $code, 'raw' => (string)$raw, 'headers' => $respHeaders];
  }

  private function decodeJson(array $res): array {
    if (empty($res['raw'])) {
      return $res + ['data' => null];
    }
    $data = json_decode((string)$res['raw'], true);
    return $res + ['data' => is_array($data) ? $data : null];
  }
}
