<?php
namespace App\Services;

use App\Exceptions\RemoteException;
use App\Helpers\Utilities\ApiFile;
use Illuminate\Support\Facades\Http;
use Exception;
use Illuminate\Support\Facades\Log;

class ApiService
{
    protected $baseUrl;
    protected $headers;

    public function __construct(string $baseUrl, array $headers = [])
    {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->headers = array_merge([
            //'Accept' => 'application/json',
            //,
        ], $headers);
    }

    public function setHeader(string $key, string $value): void
    {
        $this->headers[$key] = $value;
    }

    public function removeHeader(string $key): void
    {
        unset($this->headers[$key]);
    }

    public function setToken(string $token): void
    {
        $this->headers['Authorization'] = 'Bearer ' . $token;
    }

    private function makeRequest(string $method, string $endpoint, array $data = [], ?ApiFile $attach = null)
    {
        try {
            $url = $this->baseUrl . '/' . ltrim($endpoint, '/');
            $request = Http::withHeaders($this->headers)->timeout(30);

            if ($attach) {
                $request = $request->asMultipart()->attach(
                    $attach->fieldname, $attach->contents, $attach->filename, [
                        "Content-Type" => $attach->contentType,
                    ]
                );

                foreach ($data as $key => $value) {
                    $request = $request->attach($key, $value);
                }
            }
            else
            {
                $request->withHeaders(['Content-Type' => 'application/json'])->withBody(json_encode($data), "application/json");
            }

            $request->beforeSending(function ($request) {
                Log::debug('Request URL: ' . $request->url());
                Log::debug('Request Headers: ' . json_encode($request->headers()));
                Log::debug('Request Body: ' . $request->body());
                /*

                Log::debug('Request Method: ' . $request->method());
                Log::debug('Request Data: ' . json_encode($request->data()));
                Log::debug('Request Files: ' . json_encode($request->files()));
                Log::debug('Request Query: ' . json_encode($request->query()));
                Log::debug('Request Cookies: ' . json_encode($request->cookies()));
                Log::debug('Request Response: ' . json_encode($request->response()));
                Log::debug('Request Response Body: ' . json_encode($request->response()->body()));
                */
            });

            $response = $request->{$method}($url, $attach ? []: $data);
            if( $method == 'delete' && $response->status() == 204 ) {
                return [
                    'status' => 204,
                    'data' => [],
                    'error' => null
                ];
            }

            return [
                'status' => $response->status(),
                'data' => $response->body() ? $response->json(): [],
                'error' => null
            ];

        } catch (Exception $e) {
            throw new Exception(
                message: $e->getMessage(),
                code: $e->getCode()
            );
        }
    }

    public function get(string $endpoint, array $params = [], $attach = null)
    {
        return $this->makeRequest('get', $endpoint, $params, attach: $attach);
    }

    public function post(string $endpoint, array $data = [], $attach = null)
    {
        return $this->makeRequest('post', $endpoint, $data, attach: $attach);
    }

    public function put(string $endpoint, array $data = [], $attach = null)
    {
        return $this->makeRequest('put', $endpoint, $data, attach: $attach);
    }

    public function patch(string $endpoint, array $data = [], $attach = null)
    {
        return $this->makeRequest('patch', $endpoint, $data, attach: $attach);
    }

    public function delete(string $endpoint, array $data = [], $attach = null)
    {
        return $this->makeRequest('delete', $endpoint, $data, attach: $attach);;
    }
}
