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

namespace BplanBase\Globals\Livewire\Core\TenantExternalSystem;


use BplanBase\Globals\Livewire\Core\Global\BaseForm;
use BplanBase\Globals\Models\Tenant;
use BplanBase\Globals\Repositories\ExternalSystemRepository;
use BplanBase\Globals\Repositories\TenantRepository;
use BplanBase\Globals\Traits\ProcessesConfigTemplate;
use StdClass;


/**
 *
 * @version     1.2.0 / 2026-02-17
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class Form extends BaseForm
{


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


    use ProcessesConfigTemplate;


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


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


    /**
     * @var     array $configSections
     */
    public $configSections = [];


    /**
     * @var     null|StdClass $configSettings
     */
    public $configSettings;


    /**
     * @var     string $defaultSection
     */
    public $defaultSection = 'default';


    /**
     * @var    array $main
     */
    public $main = [
        'active'     => true,
        'client_code' => null,
        //'config_settings' => null,
        'identifier' => null,
        'external_system_id' => null,
        'synchronize' => false,
    ];


    /**
     * @var     array supportedSystemConfigTemplate
     */
    public $supportedSystemConfigTemplate;


    /**
     * @var     array supportedSystems
     */
    public $supportedSystems;


    /**
     * @var    array $tabs
     */
    public $tabs = [
        'base',
        'config-settings',
    ];


    /**
     * @var     array $tenant
     */
    public $tenant = [];


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


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


    /**
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function _initConfigSettings(): void
    {
        $this->configSettings = $this->_decodeConfigSettings($this->main['config_settings'] ?? null);

    } // _initConfigSettings()


    /**
     * Bereitet das Konfigurations-Template aus den SupportedSystems für den Aufbau des Konfigurationsformulars auf
     *
     * Für die Anlage der Konfigurations-Templates der SupportedSystems stehen verschiedene Varianten,
     * zur Auswahl. Die Templates als JSON-Array oder als JSON-Objekt eingegeben werden. Der minimale
     * Aufbau eines Templates sieht wie folgt aus.
     *
     * Als Array:
     *
     *      [
     *          {
     *              "name": "log_file"
     *          },
     *          {
     *              "name": "log_level"
     *          },
     *          {
     *              "name": "printer_name"
     *          },
     *          {
     *              "name": "temp_dir"
     *          },
     *          ...
     *      ]
     *
     * Als Objekt:
     *
     *      {
     *          "log_file": {
     *              "name": "log_file"
     *          },
     *          "log_level": {
     *              "name": "log_level"
     *          },
     *          "printer_name": {
     *              "name": "printer_name"
     *          },
     *          "temp_dir": {
     *              "name": "temp_dir"
     *          },
     *          ...
     *      }
     *
     * Für die Anzeige der Formularfelder werden mindestens ein Name und ein Label benötigt. Die
     * Angabe des label-Attributs ist trotzdem optional, weil bei ihrem Fehlen der Wert des Attributs
     * "name" verwendet wird. Genaugenommen ist bei der Objekt-Notation auch das Attribut "name"
     * bicht erforderlich, weil primär der Schlüssel verwendet wird.
     *
     * Sowohl die Array- als auch die Objekt-Variante können durch weitere Attribute angereichert
     * werden, für die Standardwerte eingesetzt werden, wenn sie fehlen.
     *
     * Folgende Attribute werden unterstützt:
     *
     *  - crypted   Steuert die Verschlüsselung der Konfigurationseinstellung.
     *              Werte: 0|1, Standard: 0
     *
     *  - default   Standardwert, der bei der Neuanlage in das Eingabefeld eingefügt wird.
     *              Werte: mixed, Standard: NULL
     *
     *              Die Anwendung dieses Parameters ist noch nicht ausimplementiert.
     *
     *  - label     Eine von "name" abweichende Zeichenkette zur Beschriftung des Eingabefeldes.
     *              Werte: string, Standard: Wert aus "name"
     *
     *  - order     Sortierreihenfolge für die Anzeige der Eingabefelder.
     *              Werte: integer, Standard: kein Standardwert
     *
     *              Elemente ohne "order" werden entsprechend ihrer Position im Template hinten an
     *              die sortierte Liste angehängt.
     *
     *              Achtung:
     *              Bei Verwendung der Objekt-Notation ist nicht gewährleistet, dass die bei der
     *              Eingabe definierte Reihenfolge der Elemente erhalten bleibt. MySQL ändert die
     *              Reihenfolge, wenn es den JSON-String in der Datenbank speichert.
     *
     *  - section   Der Name/Identifier der Formularsektion in der das Eingabefeld angezeigt werden
     *              soll.
     *              Werte: string, Standard: "default"
     *
     *  - subtype   Der Sub-Typ des Eingabefeldes.
     *              Werte: [noch nicht ausdefiniert], Standard: [noch nicht ausdefiniert]
     *
     *              Die Anwendung dieses Parameters ist noch nicht ausimplementiert.
     *              Die Idee dahinter ist, dass über diesen Wert die Validierung gesteuert wird.
     *              Beispiel: type = string, subtype = dateformat > Sicherstellung, dass ein gültiges
     *                        Datumsformat angegeben wurde.
     *
     *  - type      Der Typ des Eingabefeldes.
     *              Werte: number|string|text|toggle (noch nicht ausdefiniert), Standard: string
     *
     *              Die Anwendung dieses Parameters ist noch nicht ausimplementiert.
     *              Die Idee dahinter ist, dass über diesen Wert die Auswahl des Formularelementtyps
     *              getroffen und in Teilen vielleicht auch die Validierung gesteuert wird.
     *
     * Darüber hinaus bietet die Objekt-Variante noch die Möglichkeit ein Element mit dem Namen
     * ".meta", mit den Unterelementen "labels", "order" und "section-order", einzusetzen.
     *
     * Mit dem Unterelement "labels" ist es möglich das Formular auch mehrschprachig zu gestalten.
     * Dazu können Locale-Strings (z.B. "de_DE") als Unterschlüssel angelegt werden. Die Label
     * werden dann in Abhängigkeit von der aktuellen Sprache der Applikation ausgewählt.
     *
     * Neben den Übersetzungen für die Labels der Eingabefelder können hier auch Übersetzungen für
     * die Überschriften der Formularsektionen hinterlegt werden. Die zu verwendenden Schlüssel
     * setzen sich dabei aus dem bei der Felddefinition verwendeten section-Wert und dem Präfix
     * "section." zusammen (zum Beispiel "section.Paths").
     *
     * Beispiel:
     *
     *      {
     *          ".meta": {
     *              "labels": {
     *                  "de_DE": {
     *                      "printer_name": "Druckername",
     *                      "target": "Zielpfad",
     *                      "section.logging" => "Logging",
     *                      "section.paths" => "Pfade"
     *                  },{
     *                  "en_GB": {
     *                      "printer_name": "Printer Name",
     *                      "target": "Target-Path",
     *                      "section.logging" => "Logging",
     *                      "section.paths" => "Paths"
     *                  }
     *              }
     *          },
     *          "log_file": {
     *              "label": "Log-File",
     *              "name": "log_file",
     *              "section" => 'logging',
     *          },
     *          "log_level": {
     *              "name": "log_level",
     *              "section" => 'logging',
     *          },
     *          "printer_name": {
     *              "name": "printer_name",
     *          },
     *          "target": {
     *              "name": "target",
     *              "section": "paths"
     *          },
     *          "temp_dir": {
     *              "name": "temp_dir",
     *              "section": "paths"
     *          },
     *          ...
     *      }
     *
     * Ergebnis bei der aktuellen Applikations-Locale "de_DE":
     *
     * Formularsektion "Allgemein" (default)
     *      Feld "printer_name"      Label "Druckername"
     *
     * Formularsektion "Logging"
     *      Feld "log_file"         Label "Log-File"
     *      Feld "log_level"        Label "log_level"
     *
     * Formularsektion "Pfade"
     *      Feld "temp_dir"         Label "temp_dir"
     *      Feld "target"           Label "Zielpfad"
     *
     * Bei "order" handelt es sich um einen Array, mit dem die Reihenfolge, in der die Eingabefelder
     * im Formular angezeigt werden sollen, gesteuert werden kann.
     * Die hier angegebenen Felder werden in der angegebenen Reihenfolge ins Formular eingefügt.
     * Felder die hier nicht angegeben sind, werden am Ende angefügt.
     * Die Sortierung erfolgt unabhängig von der Sektion.
     *
     * Das meta-Element "sectionorder" erfüllt den gleichen Zweck wie das Element "order", jedoch
     * bezogen auf die Formularsektionen.
     *
     * Beispiel:
     *
     *      {
     *          ".meta": {
     *              "order": [
     *                  "printer_name",
     *                  "temp_dir",
     *                  "log_level"
     *              ],
     *              "sectionorder": [
     *                  "paths",
     *                  "logging",
     *                  "default",
     *              ],
     *
     *          },
     *          "log_file": {
     *              "label": "Log-File",
     *              "name": "log_file",
     *              "section" => 'logging',
     *          },
     *          "log_level": {
     *              "name": "log_level",
     *              "section" => 'logging',
     *          },
     *          "printer_name": {
     *              "name": "printer_name",
     *          },
     *          "target": {
     *              "name": "target",
     *              "section": "paths"
     *          },
     *          "temp_dir": {
     *              "name": "temp_dir",
     *              "section": "paths"
     *          },
     *          ...
     *      }
     *
     * Hinweis:
     * Wenn das Element ".meta > order" vorhanden ist, dann werden die order-Elemente in den
     * Felddefinitionen vollständig ignoriert.
     *
     * @todo        Mögliche weitere Optionen:
     *              - info/description
     *              - placeholder
     *
     * @todo        Generelle Validierung und Validierung auf Basis der type-Eigenschaft, muss noch
     *              implementiert werden.
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function _initSupportedSystemConfigTemplate(): void
    {
        $SupportedSystem = ExternalSystemRepository::getById($this->main['external_system_id']);

        $result = $this->_prepareConfigTemplate($SupportedSystem->configTemplate ?? null);

        $this->supportedSystemConfigTemplate = $result['template'];

        $this->configSections = array_merge(
            ['default' => __('globals::core-tenant-external-systems.section-title.default')],
            $result['sections'],
        );

    } // _initSupportedSystemConfigTemplate()


    /**
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _initSupportedSystems(): void
    {
        $this->supportedSystems = ExternalSystemRepository::getAll()
            ->pluck('label', 'id');

    } // _initSupportedSystems()


    /**
     *
     * @version     1.2.0 / 2026-02-17
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _initTenant(): void
    {
        if ($this->exists === true) {
            $Tenant = TenantRepository::getById($this->MainObject->tenant_id);

            $this->tenant = [$this->MainObject->tenant_id => $Tenant->identifier];

        } else {
            $this->main['tenant_id'] = Tenant::current()->id;

            $Tenant = TenantRepository::getById($this->main['tenant_id']);

            $this->tenant = [$this->main['tenant_id'] => $Tenant->identifier];
        }
    } // _initTenant()


    /**
     *
     * @param       bool $saveWasCreate
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onAfterSave(bool $saveWasCreate): void
    {
        parent::_onAfterSave($saveWasCreate);

        if ($saveWasCreate === true) {
            $this->_initSupportedSystemConfigTemplate();

            if ($this->supportedSystemConfigTemplate !== null) {
                $this->tabs['config-settings'] = [
                    'active' => true,
                    'identifier' => 'config-settings',
                    'label' => __($this->localeFile.'.tab-name.config-settings'),
                    'view' => 'config-settings',
                ];
            }
        }
    } // _onAfterSave()


    /**
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onBeforeValidation(): void
    {
        parent::_onBeforeValidation();

        if ($this->exists === false) {
            $this->_initSupportedSystemConfigTemplate();

            if ($this->supportedSystemConfigTemplate !== null) {
                $configSettings = [];

                foreach ($this->supportedSystemConfigTemplate as $key => $Settings) {
                    $configSettings[$key] = isset($Settings->default) ? (string) $Settings->default : '';
                }
                $this->configSettings = (object) $configSettings;

                $this->main['configSettings'] = $this->_encodeConfigSettings($this->configSettings);
            }
        } else {
            $this->main['configSettings'] = $this->_encodeConfigSettings($this->configSettings);
        }
    } // _onBeforeValidation()


    /**
     * Überschreibt die gleichnamige Methode der Base-Klasse
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function mount(): void
    {
        parent::mount();

        $this->_initSupportedSystems();
        $this->_initTenant();

        if ($this->exists === true) {
            $this->_initConfigSettings();
            $this->_initSupportedSystemConfigTemplate();

            if ($this->supportedSystemConfigTemplate === null) {
                $this->tabs['config-settings']['active'] = false;
            }
        } else {
            $this->tabs['config-settings']['active'] = false;
        }
    } // mount()


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


} // class Form extends BaseForm {}
