<?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\Global;


use BplanBase\Globals\Enums\CaseStyle;
use BplanBase\Globals\Enums\Number;
use BplanBase\Globals\Helpers\ArrayHelper;
use BplanBase\Globals\Helpers\StringHelper;
use BplanBase\Globals\Models\Tenant;
use BplanBase\Globals\Repositories\Core\TenantLocaleRepository;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\QueryException;
use Illuminate\Support\Str;
use Illuminate\Validation\Validator;
use Livewire\Component;


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


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


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


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


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


    /**
     * @var     array $activeStatus
     */
    public $activeStatus = [
        0 => '
                <svg class="h-6 w-6  text-red-500" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                  <path d="M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" stroke-linecap="round" stroke-linejoin="round" />
                </svg>',
        1 => '
                <svg class="h-6 w-6 text-green-500" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                  <path d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" stroke-linecap="round" stroke-linejoin="round" />
                </svg>',
    ];


    /**
     * Ist standardmäßig FALSE und wird auf TRUE gesetzt, wenn ein bereits gespeichertert Datensatz bearbeitet wird
     *
     * @var     bool $exists
     */
    public $exists = false;


    /**
     * @var     string $formRequestNamespace
     */
    public string|null $formRequestNamespace = null;


    /**
     * Ist standardmäßig FALSE und wird auf TRUE gesetzt, wenn ein bereits gespeichertert Datensatz bearbeitet wird
     *
     * Mit diesem Flag öässt sich steuern, dass Eingabefelder, deren Werte nach der Speicherung nicht
     * mehr geändert werden dürfen, disabled werden.
     *
     * @var     bool $freezeInput
     */
    public $freezeInput = false;


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


    /**
     *
     * @var     string $lc
     */
    public $lc;


    /**
     *
     * @var     string $localeFile
     */
    public $localeFile;


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


    /**
     * @var    string $mainID
     */
    public $mainID;


    /**
     * @var    Model $MainObject
     */
    public $MainObject;


    /**
     * @var    string $modeClass
     */
    public $modelClass;


    /**
     * Steuert die Verwendung des kombinierten Speicher-Buttons
     *
     * Standardmäßig wird der kombinierte Button verwendet (TRUE). Für Fälle, in denen ein einfacher
     * Speicher-Button erwünscht oder erforderlich ist, kann diese Variable auf FALSE gesetzt werden.
     */
    public $multiSaveButton = true;


    /**
     * @todo    Eventuell Standardwert auf "resource-id" setzen.
     *
     * @var    array $onRedirectIdName
     */
    public $onRedirectIdName = [
        'ABORT' => null,
        'CREATE' => null,
        'DELETE' => null,
        'UPDATE' => null,
    ];


    /**
     * @var    array $onRedirectParams
     */
    public $onRedirectParams = [
        'ABORT' => [],
        'CREATE' => [],
        'DELETE' => [],
        'UPDATE' => [],
    ];


    /**
     * @var    array $onRedirectRoutes
     */
    public $onRedirectRoutes = [
        'ABORT' => null,
        'CREATE' => null,
        'DELETE' => null,
        'UPDATE' => null,
    ];


    /**
     * @var    bool $readOnly
     */
    public $readOnly = false;


    /**
     * Steuert, dass auch beim Standardspeichern ein Redirect durchgeführt wird
     *
     * Normalerweise wird beim Standardspeichern das Formular nicht verlassen. In seltenen Fällen
     * (zum Beispiel bei der Neuanlage eines Tenants oder eines Users, wenn der einfache Speicher-
     * Button verwendet wird) soll aber ein Redirekt erfolgen. Durch setzen des Wertes dieser
     * Variablen auf TRUE, kann das Standardverhalten geändert werden.
     */
    public $redirectOnStandardSave = false;


    /**
     * @var     string $resourceGroup
     */
    public $resourceGroup;


    /**
     * @var    string $resourceName
     */
    public $resourceName;


    /**
     * @var     string $resourceNameSingular
     */
    public $resourceNameSingular;


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


    /**
     * @var    string $serviceClass
     */
    public $serviceClass;


    /**
     *
     */
    public $selectedTab = 'base';


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


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


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


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


    /**
     * Zentrale Methode, zur Behandlung von QueryExceptions, für alle LivewireFormComponents
     *
     * @var         QueryException $Exception
     *
     * @return      string
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _getQueryExceptionMessage(QueryException $Exception): string
    {
        $errorcode = $Exception->errorInfo[1];
        $errorlc = __('globals::'.$this->localeFile.'-form.form-error.'.$errorcode);

        if ($errorlc === 'globals::'.$this->localeFile.'-form.form-error.'.$errorcode) {
            $message = $Exception->getMessage();
        } else {
            $message = $errorlc;
        }
        $errorlc = $this->localeFile.'-form.error.'.$errorcode;
        $message = __($errorlc);

        if ($message === $this->localeFile.'-form.error.'.$errorcode) {
            $message = $Exception->getMessage();
        }
        return $message;

    } // _getQueryExceptionMessage()


    /**
     * Zentrale Methode, zur Initialisierung der Validation Rules, für alle LivewireFormComponents
     *
     * @param       Model $Model
     *
     * @param       null|string $resourceID = null
     *
     * @return      array
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _initRules(): array
    {
        $baseFormRequestNamespace = '\\BplanBase\\Globals\\Http\\Requests\\'.StringHelper::reformat($this->resourceName, CaseStyle::Studly, Number::Singular);

        if (!empty($this->mainID)) {
            $formRequestClass = $baseFormRequestNamespace.'\\UpdateRequest';

            return $formRequestClass::getRules($this->mainID, prefix: 'main');

        }
        $formRequestClass = $baseFormRequestNamespace.'\\StoreRequest';

        return $formRequestClass::getRules(prefix: 'main');

    } // _initRules()


    /**
     * Zentrale Methode, zur Initialisierung der Redirect-Einstellungen, für alle LivewireFormComponents
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _initRedirectData(): void
    {
        $idName = $this->resourceGroup.'-id';
        // $pluralResourceGroup = StringHelper::reformat($this->resourceGroup, Number: Number::Plural);

        foreach ($this->onRedirectIdName as $action => $nul) {
            if ($this->onRedirectIdName[$action] === null) {
                $this->onRedirectIdName[$action] = $idName;
            }
            if ($this->onRedirectParams[$action] === null) {
                //$this->onRedirectParams[$action]
            }
            if ($this->onRedirectRoutes[$action] === null) {
                // $this->onRedirectRoutes[$action] = 'core-'.$pluralResourceGroup.'.index';
                $this->onRedirectRoutes[$action] = 'core-'.$this->resourceName.'.index';
            }
        }

    } // _initRedirectData()


    /**
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _initTabs(): void
    {
        if (!empty($this->tabs)) {
            $tabs = $this->tabs;
            $this->tabs = [];

            foreach ($tabs as $tab) {
                $this->tabs[$tab] = [
                    'active' => true,
                    'identifier' => $tab,
                    'label' => __('globals::'.$this->localeFile.'.tab-name.'.$tab),
                    'view' => $tab,
                ];
            }
        }
    } // _initTabs()


    /**
     *
     * @return 	    void
     *
     * @version     1.2.0 / 2026-02-17
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _initTenantLocales()
    {
        if (!empty($this->tenantLocales)) {
            return;
        }
        $tenantId = Tenant::current()->id;
        /*
            @todo   Ist das hier richtig, dass auch die inaktiven Locales ermittelt werden?
        */
        $tmp = TenantLocaleRepository::determineTenantLocales($tenantId);

        $this->tenantLocales = [];

        if (!empty($tmp)) {
            $this->tenantLocales = array_flip($tmp);
        }
    } // _initTenantLocales()


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

        $systemLocales = array_flip(config('globals.system-locales'));

        ArrayHelper::ksortByArray($systemLocales, array_keys($this->tenantLocales));

        $labels = $this->main[$key];

        foreach ($systemLocales as $locale => $nul) {
            if (!isset($this->tenantLocales[$locale])) {
                continue;
            }
            $this->{$key}[$locale] = isset($labels->{$locale}) ? $labels->{$locale} : null;

            $this->localeFields[$key][] = [
                'label' => __('globals::core-global.label.main.'.$key, ['locale' => $locale]),
                'name' => 'labels.'.$locale,
            ];
        }
    } // _initLocaleFields()


    /**
     * Hook-Methode, die nach der Löschung aufgerufen wird
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::_onAfterDelete() aufgerufen wird. Auch wenn diese Methode aktuell noch leer
     * ist, kann sie doch in Zukunft irgendeine Aufgabe erfüllen.
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onAfterDelete(): void
    {
        //
    } // _onAfterDelete()


    /**
     * Hook-Methode, die nach einer erfolgreichen Speicherung der Formulardaten aufgerufen wird
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::_onAfterSave() aufgerufen wird.
     *
     * @param       bool $saveWasCreate
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onAfterSave(bool $saveWasCreate): void
    {
        if ($saveWasCreate === true) {
            $this->freezeInput = true;
        }
    } // _onAfterSave()


    /**
     * Hook-Methode, die vor der Löschung aufgerufen wird
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::_onBeforeDelete() aufgerufen wird.
     *
     * Exceptions, die von dieser Methode beziehungsweise von Methoden in abgeleiteten Klassen
     * geworfen werden, werden aufgefangen.
     *
     * @throws      Exception
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onBeforeDelete(): void
    {
        //
    } // _onBeforeDelete()


    /**
     * Hook-Methode, die vor der Speicherung aufgerufen wird
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::_onBeforeSave() aufgerufen wird. Auch wenn diese Methode aktuell noch leer
     * ist, kann sie doch in Zukunft irgendeine Aufgabe erfüllen.
     *
     * Exceptions, die von dieser Methode beziehungsweise von Methoden in abgeleiteten Klassen
     * geworfen werden, werden aufgefangen.
     *
     * @param       bool $saveIsCreate
     *
     * @throws      Exception
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onBeforeSave(bool $saveIsCreate): void
    {
        //
    } // _onBeforeSave()


    /**
     * Hook-Methode, die unmittelbar vor der Validierung aufgerufen wird
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::_onBeforeValidation() aufgerufen wird. Auch wenn diese Methode aktuell noch leer
     * ist, kann sie doch in Zukunft irgendeine Aufgabe erfüllen.
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _onBeforeValidation(): void
    {
        //
    } // _onBeforeValidation()


    /**
     *
     * @param       array $attributes
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _performServiceCreate(array $attributes): Model
    {
        $Service = new $this->serviceClass();

        return $Service->create($attributes);

    } // _performServiceCreate()


    /**
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _performServiceDelete(): Model
    {
        $Service = new $this->serviceClass();

        return $Service->delete($this->mainID);

    } // _performServiceDelete()


    /**
     *
     * @param       array $attributes
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _performServiceUpdate(array $attributes): Model
    {
        $Service = new $this->serviceClass();

        return $Service->update($this->mainID, $attributes);

    } // _performServiceUpdate()


    /**
     *
     * @return 	    void
     *
     * @version     1.0.0 / 2025-05-29
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _prepareLabelsOnBeforeValidation()
    {
        foreach ($this->labels as $locale => $label) {
            $label = trim($label);
            //  todo    Prüfen wie die Fehlermeldungen mit den Meldungen des Validators zusammengeführt werden können
            if ($label === '') {
                throw new Exception(__('validation.required', [
                        'attribute' => __('globals::global.label.main.label', ['locale' => $locale])
                    ]
                ));
            }
        }
        $defaultLabel = $this->labels[key($this->labels)];

        foreach (config('globals.system-locales') as $locale) {
            if (isset($this->tenaneLocales[$locale])) {
                continue;
            }
            /*
            **  Für die nicht verwendeten Locales wird der String der Standardsprache eingesetzt. */
            $this->labels[$locale] = $defaultLabel;
        }
        $this->main['labels'] = $this->labels;

    } // _prepareLabelsOnBeforeValidation()


    /**
     *
     * @return 	    void
     *
     * @version     1.0.0 / 2025-05-29
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _prepareTranslationsOnBeforeValidation($key, $values)
    {
        foreach ($values as $locale => $value) {
            $value = trim($value);
            //  todo    Prüfen wie die Fehlermeldungen mit den Meldungen des Validators zusammengeführt werden können
            if ($value === '') {
                throw new Exception(__('validation.required', [
                        'attribute' => __('globals::global.label.main.'.$key, ['locale' => $locale])
                    ]
                ));
            }
        }
        $defaultLabel = $values[key($values)];

        foreach (config('globals.system-locales') as $locale) {
            if (isset($this->tenantLocales[$locale])) {
                continue;
            }
            /*
            **  Für die nicht verwendeten Locales wird der String der Standardsprache eingesetzt. */
            $values[$locale] = $defaultLabel;
        }
        $this->main[$key] = $values;

    } // _prepareLabelsOnBeforeValidation()


    /**
     * Verarbeitet diverse globale Query-Parameter
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _processQueryParameters(): void
    {
        $Request = request();

        if ($Request->has('redirect-to')) {
            $this->_processRedirectToParameter($Request->input('redirect-to'));
        }
        if ($Request->has('tab')) {
            $tab = trim($Request->input('tab'));

            if (in_array($tab, $this->tabs)) {
                $this->selectedTab = $tab;
            }
        }
        if ($Request->has('highlight')) {
            $this->highlight = $Request->input('highlight');
        }
    } // _processQueryParameters()


    /**
     * Verarbeitet den "redirect-to" Query-Parameter
     *
     * Mit diesem Parameter kann gesteuert werden wohin beim Ausführen einer Formularaktion (Abbruch,
     * Löschung, Speicherung eines neuen oder vorhanden Datensatzes) umgeleitet werden soll und
     * welche Parameter dabei mitgesendet werden sollen.
     *
     * Im Normalfall steuern die Form-Components, die von dieser Klasse (BaseForm) abgeleitet sind,
     * selbstätig wohin bei der jeweiligen Aktion umgeleitet wird und welche Query-Parameter dabei
     * mitgegeben werden. Für die Fälle, in denen die Standardarbeitsweise nicht gewünscht ist, kann
     * dieser Parameter eingesetzt werden um sie zu ändern.
     *
     * Der Parameter hat den folgenden Aufbau:
     *
     *      "redirect-to" => [
     *          "a|c|d|u" => [
     *              "params" => [
     *                  "id" => $entityTypeID,
     *                  "highlight" => [
     *                      "field-id" => $resource['id'],
     *                  ],
     *                  "tab" => "fields",
     *                  ...
     *              ],
     *              "route' => "core-entity-type",
     *          ],
     *      ]
     *
     * Der Schlüssel in "redirect-to" kann eine - durch das Pipe-Symbol (|) voneinander getrennte -
     * Kombination aus den Buchstaben "a", "c", "d" und "u" sein.
     *
     * Die Buchstaben (Reihenfolge und Groß-/Kleinschreibung sind irrelevant) stehen für die
     * verschiedenen Aktionen, die durch das Bearbeitungsformular ausgeführt werden können (Abort,
     * Create, Delete, Update). Alternativ zur Angabe einzelner Buchstaben kann auch einfach der
     * Schlüssel "x" verwendet werden um alle Aktionen abzudecken.
     *
     * Das oben gezeigte Beispiel zeigt den Parameteraufbau für das Field-Form, wenn es aus
     * dem Formular für die EntityTypes heraus aufgerufen wird.
     * Die Standardarbeitsweise sieht vor, dass das Formular nach getaner Arbeit auf das Grid der
     * der Fields umleitet. Im genannten Fall ist das jedoch nicht erwünscht. Stattdessen
     * soll eine Umleitung zurück in das EntityType-Form erfolgen.
     * Das wird hier durch den Wert im Schlüssel "route" erreicht. Dabei handelt es sich um den
     * Namen der Route für das EntityTypeForm.
     *
     * Die Werte im Array "params" werden dabei als Parameter an die route()-Funktion weitergegeben.
     * route() nutzt dann den Wert aus "id" um die Route um die erforderliche ID zu ergänzen. Aus
     * dem Grund ist dort auch die ID des EntityTypes, aus dessen Formular heraus Field-Form
     * aufgerufen wurde, hinterlegt.
     * Die weiteren Werte in "params" ("field-id" und "tab") werden als Query-Parameter
     * angehängt. Bei Bedarf können hier noch weitere Parameter angehängt werden.
     *
     * Der Schlüssel "field-id" enthält im Beispiel die ID der Field, die aus der Liste zur
     * Bearbeitung ausgewählt wurde. Dieser Parameter/Wert soll dazu genutzt werden, beim
     * Wiederaufruf der Liste, den gerade bearbeiteten Datensatz identifizieren und markieren
     * (hervorheben) zu können.
     *
     * "tab" anthält den Namen des Reiters im EntityTypeForm. Mit Hilfe dieser Information ist es
     * möglich beim Rücksprung den Reiter wieder zu aktivieren.
     *
     * Das folgende Beispiel zeigt den Aufbau des Parameters für den Fall, dass aus der oben
     * beschriebenen Konstellation heraus ein neues Field angelegt werden soll:
     *
     *      'entity_type_id' => $entityTypeID,
     *      'redirect-to' => [
     *          'a|c|d|u' => [
     *              'id-name' => 'field-id',
     *              'params' => [
     *                  'id' => $entityTypeID,
     *                  'tab' => 'fields',
     *                  ...
     *              ],
     *              'route' => 'core-entity-type',
     *          ],
     *      ],
     *
     * Neu ist hier, dass neben dem "redirect-to"-Parameter noch der Parameter "entity-type-id"
     * existiert. Das FieldDefinitionForm benötigt für die Neuanlage die Zusatzinformation, für
     * welchen EntityType die neue FieldDefinition angelegt werden soll. Dazu wird hier wieder die
     * ID des aktuellen EntityTypes mitgegeben.
     *
     * Ebenfalls neu ist, dass der Schlüssel "field-id" in "param" fehlt und stattdessen
     * ein Schlüssel namens "id-name" mit dem Wert "formsection-id" existiert.
     * Da es sich um eine Neuanlege handelt, gibt es noch keine ID zur FieldDefinition. Aus dem
     * Grund ist es auch nicht möglich eine ID anzugeben. Darin angegeben ist der Name des Parameters, in
     * dem die Form-Klasse die ID des neu erzeugten Datensatzes beim Redirect ablegen soll. D, wenn sie diesen beim
     * Redirect
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _processRedirectToParameter(array $redirectTo): void
    {
        foreach ($redirectTo as $actions => $input) {
            $actions = explode('|', strtoupper($actions));

            foreach ($actions as $action) {
                if (isset($input['route'])) {
                    $this->_setRedirectRoute($action, $input['route']);
                }
                if (isset($input['params'])) {
                    $this->_setRedirectParameters($action, $input['params']);
                }
                if (isset($input['id-name'])) {
                    $this->_setRedirectIdName($action, $input['id-name']);
                }
            }
        }
    } // _processRedirectToParameter()


    /**
     * Setzt den Namen für den ID-Parameter in den Redirect-Parametern für eine Aktion
     *
     * @param       array $params
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _setRedirectIdName(string $action, string $idName): void
    {
        switch ($action) {
            case 'A':
                $this->onRedirectIdName['ABORT'] = $idName;
                break;

            case 'C':
                $this->onRedirectIdName['CREATE'] = $idName;
                break;

            case 'D':
                $this->onRedirectIdName['DELETE'] = $idName;
                break;

            case 'U':
                $this->onRedirectIdName['UPDATE'] = $idName;
                break;

            case 'X':
            default:
                $this->onRedirectIdName['ABORT'] = $idName;
                $this->onRedirectIdName['CREATE'] = $idName;
                $this->onRedirectIdName['DELETE'] = $idName;
                $this->onRedirectIdName['UPDATE'] = $idName;
        }
    } // _setRedirectIdName()


    /**
     * Setzt die Redirect-Parameter für eine Aktion
     *
     * @param       string $action
     *
     * @param       array $routeParams
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _setRedirectParameters(string $action, array $routeParams): void
    {
        switch ($action) {
            case 'A':
                $this->onRedirectParams['ABORT'] = $routeParams;
                break;

            case 'C':
                $this->onRedirectParams['CREATE'] = $routeParams;
                break;

            case 'D':
                $this->onRedirectParams['DELETE'] = $routeParams;
                break;

            case 'U':
                $this->onRedirectParams['UPDATE'] = $routeParams;
                break;

            case 'X':
            default:
                $this->onRedirectParams['ABORT'] = $routeParams;
                $this->onRedirectParams['CREATE'] = $routeParams;
                $this->onRedirectParams['DELETE'] = $routeParams;
                $this->onRedirectParams['UPDATE'] = $routeParams;
        }
    } // _setRedirectParams()


    /**
     * Setzt die Redirect-Route für eine Aktion
     *
     * @param       array $params
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _setRedirectRoute(string $action, string $routeName): void
    {
        switch ($action) {
            case 'A':
                $this->onRedirectRoutes['ABORT'] = $routeName;
                break;

            case 'C':
                $this->onRedirectRoutes['CREATE'] = $routeName;
                break;

            case 'D':
                $this->onRedirectRoutes['DELETE'] = $routeName;
                break;

            case 'U':
                $this->onRedirectRoutes['UPDATE'] = $routeName;
                break;

            case 'X':
            default:
                $this->onRedirectRoutes['ABORT'] = $routeName;
                $this->onRedirectRoutes['CREATE'] = $routeName;
                $this->onRedirectRoutes['DELETE'] = $routeName;
                $this->onRedirectRoutes['UPDATE'] = $routeName;
        }
    } // _setRedirectRoute()


    /**
     * Validiert die Formulardaten
     *
     * Diese Methode wird automatisch in der zentralen save-Methode aufgerufen.
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    protected function _validate(): array
    {
        return $this->withValidator(function (Validator $Validator)
        {
            $errors = $Validator->getMessageBag()->all();

            if (!empty($errors)) {
//                $translatedErrors = array_map(function ($item) {
//                    $details = json_decode($item);
//
//                    return __('globals::api-validation-errors.'.$details->code, (array) $details->replacements).' (Error-Code: '.$details->code.')';
//
//                }, $errors);
//
//                $this->_showNotification($translatedErrors);

                $this->_showNotification($errors);
            }
        })->validate();

    } // _validate()


    /**
     * Öffnet ein Modal-Fenster mit der Aufforderung zur Bestätigung einer Löschung
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function confirmDelete(): void
    {
        if (($caption = __('globals::'.$this->localeFile.'.confirm.delete.caption')) === 'globals::'.$this->localeFile.'.confirm.delete.caption') {
            $caption = __('globals::global.confirm.delete.caption');
        }
        if (($message = __('globals::'.$this->localeFile.'.confirm.delete.message')) === 'globals::'.$this->localeFile.'.confirm.delete.message') {
            $message = __('globals::global.confirm.delete.message');
        }
        $this->showModal(self::MODAL_TYPE__CONFIRM, 'delete', $message, $caption);

    } // confirmDelete()


    /**
     * Initiiert die Löschung eines Datensatzes
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function delete()
    {
        $this->hideModal();

        try {
            $this->_onBeforeDelete();

            $this->_performServiceDelete();

            $this->_onAfterDelete();

            return redirect()->route($this->getRedirectRoute('Delete'), $this->getRedirectParameters('Delete'));

        } catch (Exception $Exception) {
            $this->_showNotification($Exception->getMessage());
        }
    } // delete()


    /**
     * Liefert Request-Parameter für die Umleitung nach Abbruch, Löschung, Neuanlage oder Änderung
     *
     * Mit diesen Parametern wird einem Formular mitgeteilt wohin es umleiten soll, wenn die
     * Verarbeitung durch das Ausführen einer Aktion (Abbruch, Neuanlage, Löschung oder Speicherung)
     * abgeschlossen wird.
     *
     * @param       string $forAction
     *
     * @param       null|string $resourceID
     *
     * @return      null|array
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function getRedirectParameters(string $forAction, null|string $resourceID = null): null|array
    {
        $forAction = strtoupper($forAction);

        if ($resourceID === null) {
            $resourceID = $this->mainID;
        }
        $idName = $this->onRedirectIdName[$forAction];
        $actionParams = $this->onRedirectParams[$forAction];
        $actionRoute = $this->onRedirectRoutes[$forAction];

        $params = $actionParams;

        if (!isset($params['highlight'])) {
            $params['highlight'] = [];
        }
        switch ($forAction) {
            case 'ABORT':
                if ($this->exists === false) {
                    //$params['highlight'][$idName] = null;

                } else {
                    $params['highlight'][$idName] = $this->mainID;
                }
                break;

            case 'CREATE':
                $params[$idName] = $resourceID;
                $params['highlight'][$idName] = $resourceID;
                break;

            case 'DELETE':
                $params['highlight'][$idName] = $resourceID;
                break;

            case 'UPDATE':
                $params['highlight'][$idName] = $resourceID;
                break;
        }
        return $params;

    } // getRedirectParameters()


    /**
     * Liefert die Route für ein Redirect zur übergebenen Action
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function getRedirectRoute($action)
    {
        $action = strtoupper($action);

        return $this->onRedirectRoutes[$action];

    } // getRedirectRoute()


//    /**
//     * Get the error messages for the defined validation rules.
//     *
//     * @todo    Die Messages/ErrorCodes der ValidationError-Klasse sind aktuell nicht kompatibel
//     *          mit den Livewire-Components.
//     *
//     * @return      array
//     *
//     * @version     1.0.0 / 2025-05-25
//     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
//     */
//    public function messages(): array
//    {
//        return ValidationError::getErrorCodes();
//
//    } // messages()


    /**
     * Zentrale boot-Methode für alle LivewireFormComponents
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::boot() aufgerufen wird (auch wenn hier aktuell noch keine Funktionalität
     * hinterlegt ist).
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function boot()
    {
        //
    } // boot()


    /**
     * Zentrale mount-Methode für alle LivewireFormComponents
     *
     * Wenn diese Methode in einer abgeleiteten Klasse überschrieben wird, dann ist dafür zu sorgen,
     * dass dort parent::mount() aufgerufen wird.
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function mount(): void
    {
        $this->lc = config('app.locale');
        $this->resourceGroup = Str::singular($this->resourceName);

        // if ($this->resourceGroup === null) {
        //     /*
        //     **  $resourceName UND $resourceGroup gibt es nur bei den dynamischen Daten und weichen
        //     **  dort voneinander ab. Für alle anderen Typen sind die Werte der beiden variablen
        //     **  identisch. */
        //     $this->resourceGroup = $this->resourceName;
        // }
        $this->localeFile = 'core-'.StringHelper::reformat($this->resourceName, CaseStyle::Slug, Number::Plural);
        $this->resourceNameSingular = StringHelper::reformat($this->resourceName, Number: Number::Singular);

        $this->_processQueryParameters();
        $this->_initTabs();
        $this->_initRedirectData();

        if (!empty($this->MainObject->id)) {
            $this->main = $this->MainObject->toArray();
            $this->mainID = $this->MainObject->id;

            unset($this->main['id']);

            $this->exists = true;
            $this->freezeInput = true;
        }
        // $this->_initRules();

    } // mount()


    /**
     * Zentrale render-Methode für alle LivewireFormComponents
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function render()
    {
        return view('globals::livewire.core.'.$this->resourceNameSingular.'.form');

    } // render()


    /**
     * Zentrale rules-Methode für alle LivewireFormComponents
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function rules()
    {
        return $this->_initRules();

    } // rules()


    /**
     * Zentrale save-Methode für alle LivewireFormComponents
     *
     * @param       bool $returnToGrid = true
     *
     * @throws      QueryException
     *
     * @throws      Exception
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function save(bool $returnToGrid = false): void
    {
        $this->_hideNotification();

        try {
            $this->_onBeforeValidation();

            $attributes = $this->_validate();

            if ($this->exists === false) {
                $this->MainObject = new $this->modelClass();
            }
            try {
                if ($this->exists === false) {
                    try {
                        $this->_onBeforeSave(true);

                    } catch (Exception $Exception) {
                        $this->_showNotification($Exception->getMessage());
                    }
                    $saveWasCreate = true;

                    $this->MainObject = $this->_performServiceCreate($attributes['main']);
                    /*
                    **  Nach der Neuanlage müssen die Rules neu initialisiert werden. */
                    $this->_initRules();

                    $this->mainID = $this->MainObject->id;

                    $redirectRoute = $this->getRedirectRoute('Create');
                    $redirectParams = $this->getRedirectParameters('Create', $this->mainID);

                    $this->exists = true;

                } else {
                    $this->_onBeforeSave(false);

                    $saveWasCreate = false;

                    $this->MainObject = $this->_performServiceUpdate($attributes['main']);

                    $redirectRoute = $this->getRedirectRoute('Update');
                    $redirectParams = $this->getRedirectParameters('Update');
                }
                /*
                    @todo   Wenn in einer abgeleiteten Klasse nach dem Speichern noch weitere
                            Aktionen durchgeführt werden und eine davon fehlschlägt, dann kann
                            hier eine Exception auftreten.
                */
                $this->_onAfterSave($saveWasCreate);

                if ($returnToGrid === true || $this->redirectOnStandardSave === true) {
                    redirect()->route($redirectRoute, $redirectParams);
                }
                if (($message = __('globals::'.$this->localeFile.'.notification.data-saved')) === 'globals::'.$this->localeFile.'.notification.data-saved') {
                    $message = __('globals::global.notification.data-saved');
                }
                $this->_showNotification($message, self::NOTIFICATION_TYPE__SUCCESS);

            } catch (QueryException $Exception) {
                $message = $this->_getQueryExceptionMessage($Exception);

                $this->_showNotification($message);

            } catch (Exception $Exception) {
                $this->_showNotification($Exception->getMessage());
            }
        } catch (Exception $Exception) {
            $this->_showNotification($Exception->getMessage());
        }
    } // save()


    /**
     *
     * @param       string $property
     *
     * @version     1.0.0 / 2025-05-25
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public function updated(string $property): void
    {
        $this->_hideNotification();

    } // updated()

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


} // class BaseForm extends FormComponentBase {}
