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

namespace BplanBase\Globals\Repositories\Core;


use BplanBase\Globals\Helpers\EloquentHelper;
use BplanBase\Globals\Models\EntityType;
use BplanBase\Globals\Models\Tenant;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;


/**
 * Repository Class
 *
 * @version     3.2.0 / 2026-02-17
 * @author      Emilio Cannarozzo <emilio.cannarozzo@bplan-solutions.de>
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class EntityTypeRepository
{


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


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


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


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


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


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


    /**
     * Liefert eine Liste aller fremden EntityTypes, die dem übergebenen Tenant zur Verfügung stehen
     *
     * @todo        Auf die Verwendung von getSQLSelectFields() kann eigentlich verzichtet werden.
     *
     * @param       string $tenant_id
     *
     * @param       null|string $orderBy
     *
     * @return      Collection Liefert eine leere Collection, wenn es keine verfügbaren, fremden
     *              EntityTypes gibt.
     *
     * @version     3.1.0 / 2024-07-31
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function getAvailableEntityTypes(string $tenant_id, null|string $orderBy = null): Collection
    {
        $parentTenants = TenantRepository::determineParentTenantIDs($tenant_id);

        $Query = EntityType::whereIn('tenant_id', $parentTenants);

        if ($orderBy !== null) {
            $Query->orderBy($orderBy);
        }
        return $Query->get();

    } // getAvailableEntityTypes()


    /**
     * Liefert die Werte der mask-Felder des EntityTypes
     *
     * @param       string $entityTypeId
     *              Der ID zu einem EntityType.
     *
     * @return      array Liefert einen Array mit den Elementen "html" und "text".
     *
     * @version     2.0.0 / 2024-07-31
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function getMasks(string $entityTypeId): array
    {
        static $cache = [];

        $cacheKey = md5(serialize(func_get_args()));

        if (isset($cache[$cacheKey])) {
            return $cache[$cacheKey];
        }
        $Query = EntityType::selectRaw('htmlMask as html, textMask as text')
            ->where('id', '=', $entityTypeId);

        $Result = $Query->first();

        return $cache[$cacheKey] = $Result->toArray();

    } // getMasks()


    /**
     * Liefert den EntityType zur übergebenen ID
     *
     * Die Methode liefert nur dann ein Ergebnis, wenn der EntityType zum aktuellen Tenant (own)
     * oder zu einem seiner Parent-Tenants (available) gehört. Wenn eine ungültige ID übergeben wird,
     * dann wird (durch die Methode firstOrFail()) eine ModelNotFound-Exception geworfen.
     *
     * @param       string $entityTypeId
     *              Die ID zu einem EntityType.
     *
     * @throws      ModelNotFoundException
     *
     * @return      EntityType Generiert einen Status 404, wenn kein passender EntityType ermittelt
     *              werden konnte.
     *
     * @version     1.2.0 / 2026-02-17
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function getOwnOrAvailableByID(string $entityTypeId): EntityType
    {
        static $cache = [];

        $cacheKey = md5(serialize(func_get_args()));

        if (isset($cache[$cacheKey])) {
            return $cache[$cacheKey];
        }
        $tenantId = Tenant::current()->id;

        $availableEntityTypeIds = self::getAvailableEntityTypes($tenantId)
            ->pluck('id')
            ->toArray();
        /*
        **  Bedingung:  WHERE ID = ? AND (tenant_id = ? OR ID in (...))
        */
        $Query = EntityType::where('id', '=', $entityTypeId)
            ->where(function (Builder $Query) use ($availableEntityTypeIds, $tenantId) {
                $Query->where('tenant_id', '=', $tenantId)
                    // ->orWhereIn('id', $availableEntityTypeIds)
                    ;
            });

        return $cache[$cacheKey] = $Query->firstOrFail();

    } // getOwnOrAvailableByID()


    /**
     * Liefert den EntityType zur übergebenen ID
     *
     * Die Methode liefert nur dann ein Ergebnis, wenn der EntityType zum aktuellen Tenant (own)
     * gehört oder wenn er verknüpft (linked) ist. Wenn eine ungültige ID übergeben wird, dann
     * wird (durch die Methode firstOrFail()) eine ModelNotFound-Exception geworfen.
     *
     * @param       string $entityTypeId
     *              Die ID zu einem EntityType.
     *
     * @throws      ModelNotFoundException
     *
     * @return      EntityType Generiert einen Status 404, wenn kein passender EntityType ermittelt
     *              werden konnte.
     *
     * @version     1.2.0 / 2026-02-17
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function getOwnOrLinkedByID(string $entityTypeId): EntityType
    {
        static $cache = [];

        $cacheKey = md5(serialize(func_get_args()));

        if (isset($cache[$cacheKey])) {
            return $cache[$cacheKey];
        }
        $tenantId = Tenant::current()->id;

        $availableEntityTypeIds = self::getAvailableEntityTypes($tenantId)
            ->pluck('id')
            ->toArray();
        /*
        **  Bedingung:  WHERE ID = ? AND (tenant_id = ? OR ID in (...))
        */
        $Query = EntityType::where('id', '=', $entityTypeId)
            ->where(function (Builder $Query) use ($availableEntityTypeIds, $tenantId) {
                $Query->where('tenant_id', '=', $tenantId)
                    // ->orWhereIn('id', EntityTypeTenantRepository::getEntityTypeIDs($tenantId))
                    ;
            });

        return $cache[$cacheKey] = $Query->firstOrFail();

    } // getOwnOrLinkedByID()


} // class EntityTypeRepository {}
