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


use BplanBase\Globals\Enums\UserAccessLevel;
use BplanBase\Globals\Models\Role;
use BplanBase\Globals\Models\Tenant;
use BplanBase\Globals\Models\User;
use BplanBase\Globals\Models\UserRecord;
use BplanBase\Globals\Repositories\Core\RoleRepository;
use BplanBase\Globals\Repositories\Core\UserRepository;
use BplanBase\Globals\Setup\Logger;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;


if (!function_exists('get_labels')) {

    /**
     *
     * @param       array $languages
     *
     * @param       \UnitEnum $Enum
     *
     * @param       string $localeFileKey
     *
     * @param       array & $counters
     *
     * @return      string (JSON)
     *
     * @version     1.1.0 / 2026-05-17
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    function get_labels(array $languages, \UnitEnum $Enum, string $localeFileKey, array & $counters): string
    {
        $counter = ++$counters[$Enum->name];
        $labels = [];

        foreach ($languages as $langCode) {
            $labels[$langCode] = __($localeFileKey.'.'.$Enum->value, [], $langCode).' %c%';
        }
        return str_replace('%c%', $counter, json_encode($labels, JSON_UNESCAPED_UNICODE));

    } // get_labels()
}


if (!function_exists('seed_users')) {

    /**
     *
     * @param       array $users<array>
     *              Aufbau eines einzelnen Users im Array:
     *                  [
     *                      'data'     => array,
     *                      'password' => boolean|string,
     *                      'roles'    => array|NULL|TRUE
     *                  ]
     *
     *              "data"      > Hier können, abgesehen von ein paar Ausnahmen, alle Felder aus der Tabelle "users" angegeben werden.
     *              "password"  > Wenn FALSE angegeben angebenem, dann erhält der User kein Passwort.
     *                            Wenn TRUE angegeben ist, dann erhält der User in "production" ein zufällig generiertes Passwort. In
     *                            allen anderen Environments wird das Standard Development-Password aus der Konfiguration zugewiesen.
     *                            Alternativ kann auch ein Passwort im Klartext angegeben werden (unabhängig vom Environment).
     *              "roles"     > Ein Array mit Rollennamen (müssen beim Tenant des Users existieren) oder TRUE um alle verfügbaren
     *                            Rollen zuzuweisen.
     *
     * @param       int|string|null $tenantId
     *              Die ID eines Tenants. Wird NULL übergeben, dann wird der System-Tenant verwendet.
     *
     * @return      void
     *
     * @version     1.2.1 / 2026-06-09
     * @author      Emilio Cannarozzo <emilio.cannarozzo@bplan-solutions.de>
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    function seed_users(array $users, int|string|null $tenantId = null): void
    {
        $date = date('Y-m-d H:i:s');
        $env = strtolower(config('app.env'));

        $SystemTenant = Tenant::where('identifier', 'System')->first();

        $tenantId = $tenantId ?? $SystemTenant->id;

        $insertUsers = [];
        /*
        **  Spezielle Arbeitsweise
        **  Es wird überprüft ob es die definierten Standard-User nicht bereits gibt (Altsysteme). */
        foreach ($users as $user) {
            if (UserRepository::getByEmail($user['data']['email']) !== null) {
                continue;
            }
            $insertUsers[] = $user;
        }
        if (!empty($insertUsers)) {
            $developmentPassword = config('globals.dev.development-password');
            $inserts = [];
            $insertUserRecords = [];
            $insertModelHasRoles = [];
            $setupLog = '';
            /*
            **  Passworte der User definieren und User anlegen. */
            foreach ($insertUsers as $user) {
                $user['password'] ?? true;
                $user['roles'] ?? [];

                if ($user['password'] === false) {
                    $password = null;

                } else {
                    if ($user['password'] === true) {
                        if ($env === 'production') {
                            $password = Str::random(12);
                        } else {
                            $password = $developmentPassword;
                        }
                    } else {
                        $password = $user['password'];
                    }
                    $setupLog .= $user['data']['email'].'/'.$password."\n";
                }
                $user['data']['uuid']         = Str::uuid();
                $user['data']['active']       = $user['data']['active'] ?? 1;
                $user['data']['created_at']   = $date;
                $user['data']['updated_at']   = $date;
                $user['data']['access_level'] = $user['data']['access_level'] ?? UserAccessLevel::Staff;
                $user['data']['internal']     = $user['data']['internal'] ?? 0;
                $user['data']['password']     = ($password === null) ? '' : Hash::make($password);
                $user['data']['restricted']   = $user['data']['restricted'] ?? 0;
                $user['data']['tenant_id']    = $user['data']['tenant_id'] ?? $tenantId;

                $inserts[] = $user['data'];
            }
            User::insert($inserts);
            /*
            **  UserRecord-Datensätze erstellen und Rollen verknüpfen.
            **
            **  @todo   Das Thema der Rollen ist aktuell noch nicht ausdefiniert.
            **          "roles"     > [], NULL, FALSE   > keine Rollenzuordnung
            **                      > TRUE              > alle Rollen des Mandanten zuordnen
            **                      > ['#role', ...]    > alle angegebenen Rollen (nicht existente Rollen ignorieren).
            **
            **  @todo   Die aktuelle Arbeitsweise setzt voraus, dass es zu jedem Tenant eine Admin-Rolle gibt.
            **          Die sollte später automatisch bei der Anlage neuer Mandanten angelegt werden.
            */
            // $AdminRole = Role::where('tenant_id', '=', $tenantId)
            //     ->where('identifier', '=', 'Admin')
            //     ->first();
            foreach ($insertUsers as $user) {
                $User = UserRepository::getByEmail($user['data']['email'], ignoreRestriction: true);

                $name = explode(' ', $User->name, 2);

				$insertUserRecords[] = [
					'id'         => $User->id,
					'uuid'       => $User->uuid,
					'created_at' => $date,
					'updated_at' => $date,
					'email'      => $User->email,
					'first_name' => ucfirst($name[0]),
					'last_name'  => $name[1] ?? 'User',
				];
                if (empty($user['roles'])) {
                    continue;
                }
                $TenantRoles = RoleRepository::getTenantRoles($User->tenant_id, ignoreCache: true);

                $tenantRoles = array_combine($TenantRoles->pluck('name')->toArray(), $TenantRoles->toArray());

                if ($user['roles'] === true) {
                    $user['roles'] = array_keys($tenantRoles);
                }
                foreach ($user['roles'] as $role) {
                    if (!isset($tenantRoles[$role])) {
                        continue;
                    }
                    $insertModelHasRoles[] = [
                        'model_id'   => $User->id,
                        'model_type' => User::class,
                        'role_id'    => $tenantRoles[$role]['id'],
                        'tenant_id'  => $User->tenant_id,
                    ];
                }
            }
            UserRecord::insert($insertUserRecords);

            if (!empty($insertModelHasRoles)) {
                DB::table('model_has_roles')->insert($insertModelHasRoles);
            }
            Logger::log($setupLog, __FILE__);
        }
    } // seed_users()
}
