<?php
/**
 * PrintService Class
 *
 * @version     1.0.$Revision:$
 * @version     SVN: $Id:$
 * @package     bplan-base/globals
 * @subpackage  Services
 * @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\Services;


use BplanBase\Globals\Enums\PrintJobStatus;
use BplanBase\Globals\Models\PrintJob;
use BplanBase\Globals\Support\Network;
use Illuminate\Http\Client\Response;


/**
 * PrintService Class
 *
 * HTTP-Client für den PrintService-Druckdienst.
 *
 * Die Basis-URL wird nicht aus dem Profil geladen, sondern dynamisch pro
 * Drucker gesetzt. Dafür ist die Factory-Methode forHost() zu verwenden.
 *
 * Verwendung:
 *
 *   $Response = PrintService::forHost($PrintJob->printer->host)->sendJob($PrintJob);
 *
 * @version     2.2.0 / 2026-05-12
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class PrintService extends HttpService
{


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


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


    /**
     * @var     string
     */
    const ENDPOINT = '/api/{endpoint_prefix}/{name}/print';


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


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


    /**
     * @var     string
     */
    protected static string $_logPrefix = 'PrintService';


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


    /**
     * @param       string $profile
     *
     * @version     1.0.0 / 2026-04-27
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function __construct(string $profile = 'print-service')
    {
        parent::__construct($profile);

    } // __construct()


    /**
     * Ersetzt Host und Port einer URL durch die lokale IP, falls die
     * Entwicklungs-URL-Überschreibung aktiv ist.
     *
     * Ist `globals.print-service.active` false oder kein `host` konfiguriert,
     * wird die URL unverändert zurückgegeben. Bei `host = 'auto'` wird die
     * lokale IP per UDP-Socket-Trick ermittelt. Kann keine IP ermittelt
     * werden, wird die URL ebenfalls unverändert zurückgegeben.
     *
     * Der ursprüngliche Hostname wird als `_host`-Query-Parameter angehängt,
     * damit ein Apache-Reverse-Proxy die Anfrage korrekt routen kann.
     *
     * @param       string $url
     *
     * @return      string
     *
     * @version     1.0.0 / 2026-05-10
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _buildLocalUrl(string $url): string
    {
        $active = config('globals.print-service.active', true);

        if ($active !== true) {
            return $url;
        }

        $host = config('globals.print-service.host');

        if (empty($host) === true) {
            return $url;
        }

        if ($host === 'auto') {
            $host = Network::getLocalIp();

            if ($host === null) {
                return $url;
            }
        }

        $port     = (int) config('globals.print-service.port', 80);
        $parsed   = parse_url($url);

        $origHost = $parsed['host']  ?? '';
        $path     = $parsed['path']  ?? '';
        $query    = $parsed['query'] ?? '';

        $queryParts = [];

        if ($query !== '') {
            parse_str($query, $queryParts);
        }

        $queryParts['_host'] = $origHost;

        $portPart  = ($port !== 80) ? ':'.$port : '';
        $queryStr  = http_build_query($queryParts);

        return 'http://'.$host.$portPart.$path.'?'.$queryStr;

    } // _buildLocalUrl()


    /**
     * Sendet den Druckauftrag an den PrintService.
     *
     * Das `payload`-Array wird 1:1 als `params` übermittelt. `callbackURL` wird
     * aus dem PrintJob-Model ergänzt. Der Druckername ist Teil der Route und
     * wird nicht mehr im Payload übermittelt.
     *
     * @param       PrintJob $PrintJob
     *
     * @return      Response
     *
     * @version     1.3.1 / 2026-05-12
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function sendJob(PrintJob $PrintJob): Response
    {
        $PrintJob->update([
            'sent_at' => now(),
        ]);

        $endpointPrefix = $PrintJob->printer->printerType->endpoint_prefix;

        if ($endpointPrefix === null) {
            throw new \RuntimeException('PrinterType ['.$PrintJob->printer->printerType->identifier.'] has no endpoint_prefix configured.');
        }
        $endpoint = str_replace(
            ['{endpoint_prefix}', '{name}'],
            [$endpointPrefix, $PrintJob->printer->name],
            self::ENDPOINT
        );

        $controlParams = array_merge(
            (array) $PrintJob->printer->printerType->payload_template ?? [],
            (array) $PrintJob->printer->config_settings             ?? [],
        );
        $payload = array_merge($controlParams, $PrintJob->payload);

        array_walk_recursive($payload, function (mixed & $value): void {
            if (is_string($value) === true && str_starts_with($value, 'http')) {
                $value = $this->_buildLocalUrl($value);
            }
        });

        try {
            $Response = $this->post($endpoint, array_merge($payload, [
                'callbackUrl'  => $this->_buildLocalUrl($PrintJob->callback_url),
                'clientJobId'  => (string) $PrintJob->id,
            ]));

        } catch (\Throwable $e) {
            $PrintJob->update(['status' => PrintJobStatus::Failed]);

            throw $e;
        }
        $PrintJob->update(['status' => PrintJobStatus::Sent]);

        return $Response;

    } // sendJob()


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


    /**
     * Erstellt eine Instanz mit dynamisch gesetzter Basis-URL.
     *
     * @param       string $host
     *
     * @return      static
     *
     * @version     1.0.0 / 2026-04-27
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function forHost(string $host): static
    {
        $Instance = new static();

        $Instance->_config['base-url'] = $host;
        $Instance->_PendingRequest     = $Instance->_buildPendingRequest();

        return $Instance;

    } // forHost()


} // class PrintService extends HttpService {}
