<?php

namespace Alsendo\AlsendoWrapper;

use Exception;
use Isolated\Alsendo_Connect\Isolated_Guzzlehttp\GuzzleHttp\Client;
use Isolated\Alsendo_Connect\Isolated_Guzzlehttp\GuzzleHttp\Exception\GuzzleException;
use Isolated\Alsendo_Connect\Isolated_Guzzlehttp\GuzzleHttp\Exception\RequestException;
use Isolated\Alsendo_Connect\Isolated_Guzzlehttp\GuzzleHttp\Exception\ConnectException;
use InvalidArgumentException;

abstract class ApiClient
{
    protected Client $httpClient;
    protected array $config;
    protected array $options = [];

    /**
     * Initializes a new instance of the class with the provided API URL, configuration, and optional settings.
     *
     * @param string $apiUrl The base URL of the API to interact with.
     * @param array $config An associative array of configuration settings for the client.
     * @param array $options Optional configuration settings that may be used by the client for additional behavior.
     *
     * @return void
     *
     * @throws InvalidArgumentException If the provided apiUrl is not a valid string or is empty.
     * @throws InvalidArgumentException If the config array is not provided or is not an array.
     */
    public function __construct(string $apiUrl, array $config, array $options = [])
    {
        $this->config = $config;
        $this->config['apiUrl'] = $apiUrl;
        $this->httpClient = new Client(
            [
                'base_uri' => $apiUrl,
                'timeout' => 31,
                'verify' => true
            ]
        );
        $this->options = $options;
    }

    private function authorization(): void
    {

    }

    /**
     * Sends an HTTP request to the specified endpoint using the configured HTTP client.
     *
     * @param string $method The HTTP method to use (e.g., 'GET', 'POST', 'PUT', 'DELETE').
     * @param string $endpoint The endpoint path to request, relative to the base URL.
     * @param array $options Additional options to pass to the HTTP request, such as headers, query parameters, or body data.
     *
     * @return string The response body as a string.
     *
     * @throws InvalidArgumentException If the method or endpoint is not provided or invalid.
     * @throws RequestException If an HTTP request fails, such as a network error or server error.
     * @throws GuzzleException If the request fails, and no response is available, or if the response contains an error.
     */
    protected function makeRequest(string $method, string $endpoint, array $options = []): string
    {
        $options = array_merge($this->options, $options);

        try {
            $response = $this->httpClient->request($method, $endpoint, $options);
            return $response->getBody()->getContents();
        } catch (RequestException $e) {
            if ($e->hasResponse()) {
                $request = $e->getRequest();
                $responseBody = $e->getResponse()->getBody()->getContents();
                // Decode JSON and re-encode with proper Unicode handling.
                $decodedResponse = json_decode($responseBody, true);
                $readableResponse = json_encode($decodedResponse, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
                $response_code = $e->getCode();
            }

            $debug_place =  __METHOD__ . ': ' . __LINE__;
            $this->log_for_woocommerce($debug_place, $response_code, $request, $method, $endpoint, $readableResponse, $options );
            
            throw new \RuntimeException($readableResponse );
        }
    }


    public function log_for_woocommerce($debug_place, $response_code, $request, $method, $endpoint, $readableResponse, $options){

        if ( function_exists( 'wc_get_logger' ) ) {

            $order_id = ! empty( $_POST['order_id'] ) && is_numeric( $_POST['order_id'] ) ? $_POST['order_id'] : '';

            unset($options['headers']);

            \wc_get_logger()->debug(print_r('WRAPPER makeRequest EXCEPTION', true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('debug_place: ' . $debug_place, true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('Request_Method: ' . $request->getMethod(), true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('Request_URL: ' . $request->getUri(), true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('Method: ' . $method, true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('Endpoint: ' . $endpoint, true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('Response code: ' . $response_code, true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('ReadableResponse: ', true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r($readableResponse, true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r('Options: ', true), array('source' => 'alsendo-connect-order-' . $order_id));
            \wc_get_logger()->debug(print_r($options, true), array('source' => 'alsendo-connect-order-' . $order_id));
        }
    }

}
