<?php
/*
 * UJS REST-v1 Beispiel als einbindbare PHP-Klasse.
 *
 * Kompatibel mit PHP 5.5 bis PHP 8.x.
 * Abhaengigkeiten: ext-curl, ext-json.
 *
 * Verwendung:
 * 1. Diese Datei herunterladen/kopieren.
 * 2. Im Zielprojekt als example_classe.php speichern.
 * 3. Zugangsdaten unten im Konfigurationsblock einsetzen.
 *
 * Direkt testen:
 *
 *   php example_classe.php
 *
 * Einbindung in ein Projekt:
 *
 *   require_once 'example_classe.php';
 *   $ujs = new UjsExampleClient('https://dev.jsonstorage.de', 'TOKEN', 'testmodul');
 *   $result = $ujs->store('test_note', 'TEST-1001', array('title' => 'Hallo'), array('testmodul'));
 */

/*
 * Zugangsdaten für den Beispielaufruf.
 * Einen echten Token hier nur lokal eintragen, nicht in eine öffentlich
 * abrufbare Datei schreiben.
 */
$ujsExampleBaseUrl = 'https://dev.jsonstorage.de';
$ujsExampleModule = 'testmodul';
$ujsExampleToken = '2618a9dd9eba3515b50c427d66e5635b1bda91cf443e51ce';

if (!class_exists('UjsExampleClient')) {
    class UjsExampleClient
    {
        private $baseV1;
        private $token;
        private $moduleSlug;

        public function __construct($baseUrl, $token, $moduleSlug)
        {
            $this->baseV1 = rtrim($baseUrl, '/') . '/api/v1';
            $this->token = $token;
            $this->moduleSlug = $moduleSlug;
        }

        public function whoami()
        {
            return $this->request('GET', '/whoami');
        }

        public function listEntries($query)
        {
            return $this->request('GET', '/modules/' . rawurlencode($this->moduleSlug) . '/entries', $query);
        }

        public function store($type, $customerNo, $data, $tags)
        {
            return $this->request('POST', '/modules/' . rawurlencode($this->moduleSlug) . '/entries', array(), array(
                'type' => $type,
                'customer_no' => $customerNo,
                'data' => $data,
                'tags' => $tags,
            ));
        }

        public function get($id)
        {
            return $this->request('GET', '/modules/' . rawurlencode($this->moduleSlug) . '/entries/' . (int)$id);
        }

        public function update($id, $patch, $ifVersion)
        {
            $headers = array();
            if ($ifVersion !== null) {
                $headers[] = 'If-Match: "v' . (int)$ifVersion . '"';
            }

            return $this->request('PUT', '/modules/' . rawurlencode($this->moduleSlug) . '/entries/' . (int)$id, array(), $patch, $headers);
        }

        public function history($id, $limit, $offset)
        {
            return $this->request('GET', '/modules/' . rawurlencode($this->moduleSlug) . '/entries/' . (int)$id . '/history', array(
                'limit' => (int)$limit,
                'offset' => (int)$offset,
            ));
        }

        public function aggregate($query)
        {
            return $this->request('GET', '/modules/' . rawurlencode($this->moduleSlug) . '/aggregate', $query);
        }

        public function delete($id)
        {
            return $this->request('DELETE', '/modules/' . rawurlencode($this->moduleSlug) . '/entries/' . (int)$id);
        }

        private function request($method, $path, $query = array(), $body = null, $extraHeaders = array())
        {
            if (!function_exists('curl_init')) {
                return array('success' => false, 'error' => 'PHP extension curl fehlt', '_status' => 0);
            }

            $url = $this->baseV1 . $path;
            $queryString = $this->buildQuery($query);
            if ($queryString !== '') {
                $url .= '?' . $queryString;
            }

            $rawBody = $body !== null ? json_encode($body) : '';
            $headers = array(
                'Authorization: Bearer ' . $this->token,
                'X-Request-ID: example-' . str_replace('.', '', uniqid('', true)),
            );
            foreach ($extraHeaders as $header) {
                $headers[] = $header;
            }
            if ($rawBody !== '') {
                $headers[] = 'Content-Type: application/json';
            }

            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            if ($rawBody !== '') {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $rawBody);
            }

            $response = curl_exec($ch);
            $error = curl_error($ch);
            $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            if ($response === false) {
                return array('success' => false, 'error' => $error ? $error : 'cURL request failed', '_status' => 0);
            }

            $decoded = json_decode($response, true);
            $out = is_array($decoded) ? $decoded : array('raw' => $response);
            $out['_status'] = $status;
            return $out;
        }

        private function buildQuery($query)
        {
            $clean = array();
            if (!is_array($query)) {
                return '';
            }

            foreach ($query as $key => $value) {
                if ($value !== null && $value !== '') {
                    $clean[$key] = $value;
                }
            }

            return $clean ? http_build_query($clean) : '';
        }
    }
}

if (!function_exists('ujs_example_class_print')) {
    function ujs_example_class_print($title, $data)
    {
        echo "\n=== " . $title . " ===\n";
        echo json_encode($data, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0) . "\n";
    }
}

if (!function_exists('ujs_example_class_fail')) {
    function ujs_example_class_fail($message)
    {
        if (PHP_SAPI === 'cli' && defined('STDERR')) {
            fwrite(STDERR, $message . "\n");
        } else {
            if (!headers_sent()) {
                header('Content-Type: text/plain; charset=utf-8');
                http_response_code(400);
            }
            echo $message . "\n";
        }
        exit(1);
    }
}

if (isset($_SERVER['SCRIPT_FILENAME']) && realpath($_SERVER['SCRIPT_FILENAME']) === realpath(__FILE__)) {
    if (PHP_SAPI !== 'cli' && !headers_sent()) {
        header('Content-Type: text/plain; charset=utf-8');
    }

    $baseUrl = getenv('UJS_BASE_URL') ? getenv('UJS_BASE_URL') : $ujsExampleBaseUrl;
    $module = getenv('UJS_MODULE') ? getenv('UJS_MODULE') : $ujsExampleModule;
    $token = getenv('UJS_TOKEN') ? getenv('UJS_TOKEN') : $ujsExampleToken;

    if ($token === '') {
        ujs_example_class_fail("Bitte im Konfigurationsblock \$ujsExampleToken setzen oder UJS_TOKEN übergeben.");
    }

    $client = new UjsExampleClient($baseUrl, $token, $module);
    ujs_example_class_print('Token prüfen', $client->whoami());

    $created = $client->store('test_note', 'TEST-1001', array(
        'title' => 'UJS Testeintrag',
        'status' => 'open',
        'created_by' => 'example_classe.php',
        'amount' => 129.90,
    ), array('testmodul', 'php-class'));
    ujs_example_class_print('Eintrag erstellen', $created);

    $id = isset($created['entry']['id']) ? (int)$created['entry']['id'] : 0;
    if ($id > 0) {
        ujs_example_class_print('Eintrag lesen', $client->get($id));
        ujs_example_class_print('Liste filtern', $client->listEntries(array(
            'customer_no' => 'TEST-1001',
            'q[data.status]' => 'open',
            'limit' => 10,
        )));
        ujs_example_class_print('Eintrag aktualisieren', $client->update($id, array(
            'data' => array(
                'title' => 'UJS Testeintrag',
                'status' => 'done',
                'created_by' => 'example_classe.php',
                'amount' => 129.90,
            ),
            'tags' => array('testmodul', 'php-class', 'done'),
        ), isset($created['entry']['version']) ? (int)$created['entry']['version'] : null));
        ujs_example_class_print('Historie', $client->history($id, 100, 0));
        ujs_example_class_print('Aggregation', $client->aggregate(array(
            'agg' => 'sum',
            'field' => 'amount',
            'group_by' => 'customer_no',
        )));
    }
}