<?php

namespace Oney\ThreeByFour\Model\Api;

use Exception;
use Magento\Framework\HTTP\Client\Curl;
use Magento\Framework\Message\ManagerInterface;
use Oney\ThreeByFour\Helper\Config as HelperConfig;
use Oney\ThreeByFour\Logger\Logger;
use Magento\Framework\App\Http\Context;

abstract class ApiAbstract
{
    /**
     * @var Curl
     */
    protected $client;

    protected $api_url;

    protected $params;
    /**
     * @var HelperConfig
     */
    protected $_helperConfig;
    /**
     * @var Logger
     */
    protected $_logger;
    /**
     * @var ManagerInterface
     */
    protected $_messageManager;
    /**
     * @var array
     */
    protected $_headers;

    /**
     * @param Curl             $client
     * @param HelperConfig     $config
     * @param Logger           $logger
     * @param ManagerInterface $messageManager
     */
    public function __construct(
        Curl $client,
        HelperConfig $config,
        Logger $logger,
        ManagerInterface $messageManager
    )
    {
        $this->client = $client;
        $this->_helperConfig = $config;
        $this->_logger = $logger;
        $this->_messageManager = $messageManager;
    }

    /**
     * @param string $method
     * @param string $url
     *
     * @return string
     * @throws Exception
     */
    protected function call(string $method = "GET", string $url = ""): string
    {
        try {
            $this->addHeader('Content-Type', 'application/json');
            $this->client->setHeaders($this->_headers);
            
            $this->_logger->info("[SUCCESS] [" . $method . "] Marketing API 1.1 - Request headers: ", [
                'headers' => $this->_headers
            ]);
            $this->_logger->info("[SUCCESS] [" . $method . "] Marketing API 1.1 - Request params: ", [
                'params' => $this->params
            ]);

            $this->executeRequest($method, $url);
            
            $statusCode = $this->client->getStatus();
            $responseBody = $this->client->getBody();
            
            if ($statusCode !== 200) {
                $this->_logger->error("[ERROR] [" . $method . "] Marketing API 1.1 - Request failed: ", [
                    'status' => $statusCode,
                    'url' => $url,
                    'body' => json_decode($responseBody, true)
                ]);
                throw new Exception("API request failed with status: " . $statusCode);
            }
            
            $this->_logger->info("[SUCCESS] [" . $method . "] Marketing API 1.1 - Response received: ", [
                'status' => $statusCode,
                'body' => json_decode($responseBody, true)
            ]);
            
            return $responseBody;
            
        } catch (Exception $e) {
            $this->_logger->error("[ERROR] [" . $method . "] Marketing API 1.1 - Exception: ", [
                'url' => $url,
                'error' => $e->getMessage()
            ]);
            throw $e;
        }
    }

    /**
     * Execute the HTTP request based on method
     *
     * @param string $method
     * @param string $url
     * @return void
     */
    private function executeRequest(string $method, string $url): void
    {
        if ($method === "GET" && !empty($this->params)) {
            $urlWithParams = $this->buildUrlWithParams($url);
            $this->client->get($urlWithParams);
        } elseif ($method === "POST") {
            $this->_logger->info("[SUCCESS] [" . $method . "] Marketing API 1.1 - Request body: ", [
                'url' => $url,
                'body' => $this->params
            ]);
            $this->client->post($url, json_encode($this->params));
        }
    }

    /**
     * Build URL with query parameters
     *
     * @param string $url
     * @return string
     */
    private function buildUrlWithParams(string $url): string
    {
        $url .= "?";
        $i = 0;
        foreach ($this->params as $param => $value) {
            if ($i++ !== 0) $url .= '&';
            $url .= $param . "=" . urlencode($value);
        }
        return $url;
    }

    protected function setHeaders(array $headers): self
    {
        $this->_headers = $headers;
        return $this;
    }

    protected function addHeader(string $name, string $value): self
    {
        $this->_headers[$name] = $value;
        return $this;
    }

    public function setParams(array $params): self
    {
        $this->params = $params;
        return $this;
    }

    public function addParam(string $param, $value): self
    {
        $this->params[$param] = $value;
        return $this;
    }
}
