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

namespace BplanBase\Globals\Http\Middleware;


use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;


/**
 * Middleware Class
 *
 * @version     1.4.0 / 2025-02-08
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class LogApiRequest
{


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


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


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


    /**
     * @var         int $_logLevel
     */
    private $_logLevel;


    /**
     * @var         int $_status
     */
    private $_status;


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


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


    /**
     * Bestimme das dynamische Log-Level basierend auf API_LOG_LEVEL und HTTP-Statuscode.
     *
     * @return      string
     *
     * @version     1.0.0 / 2024-11-05
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    private function _determineLogLevel(): string
    {
        /*
        **  Im Fehlerfall wird immer als "error" geloggt. */
        if ($this->_status < 200 || $this->_status >= 300) {
            return 'error';
        }
        /*
        **  Im Normalfall erfolgt das Logging entsprechend der Konfigurationseinstellung (globals.api.log-level/API_LOG_LEVEL). */
        return match ($this->_logLevel) {
            1       => 'notice',  //  Minimale Log-Daten
            2       => 'info',    //  Erweiterte Log-Daten
            3       => 'debug',   //  Vollständige Log-Daten

            default => 'info',
        };
    } // _determineLogLevel()


    /**
     * Handle an incoming request and log based on API_LOG_LEVEL.
     *
     * @param       \Illuminate\Http\Request  $request
     *
     * @param       \Closure  $next
     *
     * @return      mixed
     *
     * @version     1.3.0 / 2025-02-08
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function handle(Request $Request, Closure $next)
    {
        $random = Str::random(6);
        /*
        **  Eingestellten Log-Level ermitteln. */
        $this->_logLevel = (int) config('globals.api.log-level', 0);

        if ($this->_logLevel >= 2) {
            /*
            **  Bei Log-Level 2 die Header- und Request-Daten hinzufügen.
            **  Die Daten werden bereits hier ermittelt, da sie durch Weiterreichen des Requests
            **  teilweise verändert werden. */
            $requestBody = $Request->all();
            $requestHeaders = $Request->headers->all();
        }
        /*
        **  Weiterleiten des Requests und Erfassung der Response. */
        $Response = $next($Request);

        if ($this->_logLevel === 0) {
            return $Response;
        }
        $this->_status = $Response->status();
        /*
        **  Log-Level für die Log-Datei ermitteln. */
        $logLevel = $this->_determineLogLevel($this->_status);
        /*
        **  Minimale/generelle Log-Daten zusammenstellen. */
        $logData = [
            'method' => $Request->method(),
            'status' => $this->_status,
            'route' => $Request->path(),
            'query' => $Request->query(),
        ];
        $failure = false;
        /*
        **  Fehlerstatus prüfen. */
        if ($this->_status < 200 && $this->_status >= 300) {
            $failure = true;
        }
        /*
        **  Im Fehlerfall oder in Abhängigkeit vom eingestellten Log-Level die Log-Daten ergänzen. */
        if ($failure === true || $this->_logLevel >= 2) {
            if ($this->_logLevel >= 4) {
                $requestBody = print_r($requestBody, true);
            }
            /*
            **  Im Fehlerfall oder bei Log-Level 2 die Header- und Request-Daten hinzufügen. */
            $logData['headers'] = $requestHeaders;
            $logData['request_body'] = $requestBody;
        }
        Log::channel('api')->log($logLevel, 'API Request  ['.$random.'/Request] ', $logData);

        if ($failure === true || $this->_logLevel >= 3) {
            /*
            **  Im Fehlerfall oder bei Log-Level 3 wird ein zusätzlicher Log-Eintrag mit den Response-Daten
            **  erzeugt. */
            $logData = [
                'method' => $Request->method(),
                'status' => $this->_status,
            ];
            /*
            **  Im Fehlerfall oder bei Log-Level 3 auch noch die Response-Daten hinzufügen. */
            $logData['response'] = (array) json_decode(str_replace('\\"', '"', $Response->getContent()));

            Log::channel('api')->log($logLevel, 'API Response ['.$random.'/Response]', $logData);
        }
        return $Response;

    } // handle()


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


} // class LogApiRequest {}
