<?php

namespace classes;

require_once WD . '/modules/shelly/shelly_c.php';
/** Actions */
require_once WD . '/modules/shelly/actions/shelly_search_a.php';

use Exception;
use interfaces\shelly_i;
use shelly\actions\shelly_search_a;
use shelly\shelly_c;

class shelly implements shelly_i
{
    /**
     * Configuration of the shelly module
     * @var shelly_c
     */
    public shelly_c $config;

    /**
     * ACTION: shelly_SEARCH
     * @see shelly_search_a
     * @notation This action is when a company search request is made, and logs the request in the database
     * @var shelly_search_a $shelly_search
     */
    private shelly_search_a $shelly_search;

    public function __construct()
    {
        $this->config = new shelly_c();
        /** Actions */
        $this->shelly_search = new shelly_search_a();
    }

    /**
     * @inheritDoc
     * @throws Exception If the module is not enabled, the license plate is invalid, the daily limit is exceeded, or the secret key is invalid
     */
    function sendRequest(
        string $endpoint,
        array  $data = [],
        string $method = 'GET'
    ): object
    {
        // Validate the module is enabled
        self::requireModuleEnabled();
        // Validate the secret key
        self::requireValidSecretKey();
        // Send the request
        $response = match ($method) {
            //'GET' => self::sendGetRequest($endpoint, $data),
            'POST' => self::sendPostRequest($endpoint, $data),
            //'PUT' => self::sendPutRequest($endpoint, $data),
            //'DELETE' => self::sendDeleteRequest($endpoint, $data),
            default => self::exception(
                [
                    'method' => $method,
                    'endpoint' => $endpoint,
                    'data' => $data,
                    'response' => null,
                    'status_code' => 400,
                    'error' => 'Invalid request method',
                ],
                500
            ),
        };
        // Add the usage to the request log
        $this->shelly_search->shelly_search($response, 200);
        // Return the response
        return $response;
    }

    /**
     * @inheritDoc
     */
    function requireModuleEnabled(): void
    {
        // Check if the module is enabled
        if (!$this->config->enabled->isTrue()) {
            throw new Exception('The shelly module is not enabled');
        }
    }


    /**
     * @inheritDoc
     */
    function requireValidSecretKey(): void
    {
        // Check if the secret key is valid
        if ($this->config->secret_key->getVariableValue() === null) {
            self::exception(
                [
                    'status_code' => 500,
                    'error' => 'Invalid secret key defined in the config (shelly_secret_key_c)',
                ],
                500
            );
        }
    }

    /**
     * @throws Exception
     */
    function exception(array $data, int $status_code = 500): object
    {
        // Check if the response is valid JSON
        if (!json_decode($data['response'])) {
            throw new Exception('Invalid response');
        }
        // Add the request to the log
        $this->shelly_search->shelly_search($data, $status_code);;
        return throw new Exception($data['error'] ?? 'An error occurred while processing the request, in ' . $this->config->getModuleName() . ' module');
    }

    /**
     * @inheritDoc
     * @throws Exception
     */
    function requireValidServerURL(): void
    {
        // Check if the server URL is valid
        if ($this->config->server_url->getVariableValue() === null) {
            self::exception(
                [
                    'status_code' => 500,
                ]
            );
        }
    }

    /**
     * @inheritDoc
     * @throws Exception
     */
    function sendPostRequest(string $endpoint, array $data): array|object|null
    {
        /**
         * curl -X POST 'https://<HOST>/v2/devices/api/get?auth_key=<AUTH_KEY>' \
         * -H 'Content-Type: application/json' \
         * -d '<BODY>'
         */
        // Require the module to be enabled
        self::requireModuleEnabled();
        self::requireValidSecretKey();
        self::requireValidServerURL();
        // Send the request
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, self::appendAuthKeyToQuery($this->config->server_url->getVariableValue() . $endpoint));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
        ]);
        // Execute the request
        $response = curl_exec($ch);
        // Get the status code
        $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        // Check for errors
        if (curl_errno($ch)) {
            self::exception(
                [
                    'method' => 'POST',
                    'endpoint' => $endpoint,
                    'data' => $data,
                    'response' => $response,
                ],
                $status_code
            );
        }
        // Close the cURL session
        curl_close($ch);
        // Check if there is a response (some endpoints don't return a response)
        if ($response === false) {
            return null;
        }
        // Return the response
        return json_decode($response);
    }

    function appendAuthKeyToQuery(string $url): string
    {
        return $url . '?auth_key=' . $this->config->secret_key->getVariableValue();
    }
}