<?php
/**
 * Token Trait
 *
 * @version     1.0.$Revision:$
 * @version     SVN: $Id:$
 * @package     bplan-base/globals
 * @subpackage  Traits
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 * @copyright   Copyright (C) 2025 bplan-solutions GmbH & Co. KG <http://www.bplan-solutions.de/>
 * /Δ\
 */

namespace BplanBase\Globals\Traits;


/**
 * Token Trait
 *
 * Trait für den Einsatz im Model-Observer.
 * Beim Einsatz muss die Observer-Klasse die folgenden Konstanten definieren.
 * - MODEL_CLASS    Standardmäßig bei allen automatisch erzeugten Observer-Klassen vorhanden (z.B. const MODEL_CLASS = Appointment::class;)
 * - TOKEN_LENGTH   Die Gesamtlänge des Tokens, inklusive eventuell vorhandenem Präfix (int).
 * - TOKEN_NAME     Name des Token-Feldes in der Datenbank (optional, string, Standard "token").
 *
 * @version     1.0.0 / 2025-03-18
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
trait ModelHasToken
{


/* +++ TRAITS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS CONSTANTS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT MEMBERS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS MEMBERS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT METHODS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS METHODS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * Erzeugt ein eindeutiges Token
     *
     * @version     1.0.0 / 2025-03-18
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    private static function _generateUniqueToken(): string
    {
        /*
        **  Die Schleife läuft solange bis ein eindeutiges Token gefunden wurde. */
        do {
            /*
            **  Die Range für das Token ermitteln und eine eine zufällige Zahl innerhalb der Range erzeugen. */
            $intLength = self::TOKEN_LENGTH - strlen(self::TOKEN_PREFIX);

            $randomInt = (string) random_int((int) '1'.str_repeat('0', $intLength - 1), (int) str_repeat('9', $intLength));
            /*
            **  Präfix voranstellen. */
            $token = self::TOKEN_PREFIX.$randomInt;

        } while (self::_tokenExists($token));

        return $token;

    } // _generateUniqueToken()


    /**
     * Sucht das übergebene Token in der Datenbank
     *
     * Diese Methode kann in der Klasse überschrieben werden, wenn weitere Parameter für
     * die Überprüfung der Tokens erforderlich sind.
     *
     * @param       string $token
     *
     * @return 	    bool
     *
     * @version     1.0.0 / 2025-03-18
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    private static function _searchToken(string $token): bool
    {
        $tokenName = defined('self::TOKEN_NAME') ? self::TOKEN_NAME : 'token';

        return with(new (self::MODEL_CLASS)())->where($tokenName, '=', $token)
            ->exists();

    } // _searchToken()


    /**
     * Überprüft ob das übergebene Token bereits verwendet wird
     *
     * @param       string $token
     *
     * @return      bool
     *
     * @version     1.0.0 / 2025-03-18
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    private static function _tokenExists(string $token): bool
    {
        static $cache = [];

        $cacheKey = md5(serialize(func_get_args()));

        if (isset($cache[$cacheKey])) {
            return $cache[$cacheKey];
        }
        return $cache[$cacheKey] = self::_searchToken($token);

    } // _tokenExists()


} // trait ModelHasToken {}
