<?php

namespace kernel;

use Illuminate\Database\Eloquent\Model;
use kernel\helpers\Debug;
use kernel\models\Option;
use kernel\modules\option\service\OptionService;
use kernel\services\ModuleService;

class EntityRelation
{
    protected ModuleService $moduleService;

    public function __construct()
    {
        $this->moduleService = new ModuleService();
    }


    public static function getEntityList(): array
    {
        $list = [];
        $moduleService = new ModuleService();
        $activeModules = $moduleService->getActiveModules();
        foreach ($activeModules as $module) {
            if (isset($module['type']) and $module['type'] === "entity") {
                $list[$module['slug']] = $module['slug'];
            }
        }

        return $list;
    }

    public function getAdditionalPropertyList(): array
    {
        $list = [];
        $activeModules = $this->moduleService->getActiveModules();
        foreach ($activeModules as $module) {
            if (isset($module['type']) and $module['type'] === "additional_property") {
                $list[] = $module['slug'];
            }
        }

        return $list;
    }

    public static function getEntitiesRelations(): array|bool
    {
        $entity_relations = OptionService::getItem("entity_relations");
        if ($entity_relations) {
            return json_decode($entity_relations, true);
        }

        return false;
    }

    public static function removePropertyFromEntityRelations(string $entity, string $property): bool
    {
        $entity_relations_info = Option::where("key", "entity_relations")->first();
        if ($entity_relations_info) {
            $entity_relations = json_decode($entity_relations_info->value, true);
            if ($entity_relations[$entity]) {
                $propertyKey =  array_search($property, $entity_relations[$entity]);
                if ($entity_relations[$entity][$propertyKey] === $property) {
                    unset($entity_relations[$entity][$propertyKey]);
                    $entity_relations[$entity] = array_values($entity_relations[$entity]);
                    if (empty($entity_relations[$entity])) {
                        unset($entity_relations[$entity]);
                    }
                    $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
                    $entity_relations_info->save();
                    return true;
                }
            }
        }

        return false;
    }

    public static function removePropertyRelation(string $property): bool
    {
        $entity_relations_info = Option::where("key", "entity_relations")->first();
        if ($entity_relations_info) {
            $entity_relations = json_decode($entity_relations_info->value, true);
            foreach ($entity_relations as $entity => $entity_relation) {
                if (in_array($property, $entity_relation)) {
                    $index = array_search($property, $entity_relation);
                    unset($entity_relations[$entity][$index]);
                }
            }
            $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
            $entity_relations_info->save();

            return true;
        }

        return false;
    }

    public static function removeEntityRelation(string $entity): bool
    {
        $entity_relations_info = Option::where("key", "entity_relations")->first();
        if ($entity_relations_info) {
            $entity_relations = json_decode($entity_relations_info->value, true);
            if (isset($entity_relations[$entity])) {
                unset($entity_relations[$entity]);
                $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
                $entity_relations_info->save();
                return true;
            }
        }

        return false;
    }

    public function getEntityRelationsBySlug(string $slug)
    {
        $entityRelations = $this->getEntitiesRelations();
        if ($entityRelations) {
            if (isset($entityRelations[$slug])) {
                return $entityRelations[$slug];
            }
        }

        return [];
    }

    public static function addEntityRelation(string $entity, string $property): bool
    {
        $entity_relations_info = Option::where("key", "entity_relations")->first();
        if ($entity_relations_info) {
            $entity_relations = json_decode($entity_relations_info->value, true);
            if (isset($entity_relations[$entity])) {
                $entity_relations[$entity][] = $property;
            } else {
                $entity_relations[$entity][] = $property;
            }
            $entity_relations_info->value = json_encode($entity_relations, JSON_UNESCAPED_UNICODE);
            $entity_relations_info->save();

            return true;
        }

        return false;
    }

    public function getAdditionalPropertyClassBySlug(string $slug)
    {
        $module = $this->moduleService->getModuleInfoBySlug($slug);
        if (isset($module['module_class'])) {
            return new $module['module_class']();
        }

        return false;
    }

    public function renderFormInputsBySlug(string $entity, string $slug, Model $model): void
    {
        $moduleClass = $this->getAdditionalPropertyClassBySlug($slug);
        if ($moduleClass and method_exists($moduleClass, "formInputs")) {
            $moduleClass->formInputs($entity, $model);
        }
    }

    public function renderEntityAdditionalPropertyFormBySlug(string $entity, Model $model = null): void
    {
        $relations = $this->getEntityRelationsBySlug($entity);
        if ($relations) {
            foreach ($relations as $relation) {
                $this->renderFormInputsBySlug($entity, $relation, $model);
            }
        }
    }

    public function saveEntityRelationBySlug(string $slug, string $entity, Model $model, Request $request): void
    {
        $moduleClass = $this->getAdditionalPropertyClassBySlug($slug);
        if ($moduleClass and method_exists($moduleClass, "saveInputs")) {
            $moduleClass->saveInputs($entity, $model, $request);
        }
    }

    public function saveEntityRelation(string $entity, Model $model, Request $request): void
    {
        $relations = $this->getEntityRelationsBySlug($entity);
        if ($relations) {
            foreach ($relations as $relation) {
                $this->saveEntityRelationBySlug($relation, $entity, $model, $request);
            }
        }
    }

    public function getEntityAdditionalProperty(string $entity, Model $model): array
    {
        $relations = $this->getEntityRelationsBySlug($entity);
        if ($relations) {
            $relationsArr = [];
            foreach ($relations as $relation) {
                $moduleClass = $this->getAdditionalPropertyClassBySlug($relation);
                if ($moduleClass and method_exists($moduleClass, "getItems")) {
                    $relationsArr[$relation] = $moduleClass->getItems($entity, $model);
                }
            }

            return $relationsArr;
        }

        return [];
    }

    public function getAdditionalPropertyByEntityId(string $entity, string $entity_id, string $additionalPropertySlug): string
    {
        $moduleClass = $this->getAdditionalPropertyClassBySlug($additionalPropertySlug);
        if ($moduleClass and method_exists($moduleClass, "getItem")) {
            return $moduleClass->getItem($entity, $entity_id);
        }

        return "";
    }

    public function deleteEntityRelationBySlug(string $slug, string $entity, Model $model): void
    {
        $moduleClass = $this->getAdditionalPropertyClassBySlug($slug);
        if ($moduleClass and method_exists($moduleClass, "deleteItems")) {
            $moduleClass->deleteItems($entity, $model);
        }
    }

    public function deleteEntityRelation(string $entity, Model $model): void
    {
        $relations = $this->getEntityRelationsBySlug($entity);
        if ($relations) {
            foreach ($relations as $relation) {
                $this->deleteEntityRelationBySlug($relation, $entity, $model);
            }
        }
    }

    public static function getEntityByProperty(string $data): array
    {
        $entityRelations = self::getEntitiesRelations();
        $entities = [];
        foreach ($entityRelations as $entity => $property) {
            if (in_array($data, $property)) {
                $entities[] = $entity;
            }
        }

        return $entities;
    }

    public static function configurationEntitiesByProperty(array|null $entities, string $property): void
    {
        $entityRelations = self::getEntitiesRelations();
        if (isset($entities)) {
            foreach ($entities as $entity) {
                if (!isset($entityRelations[$entity])) {
                    EntityRelation::addEntityRelation($entity, $property);
                }
            }
            foreach ($entityRelations as $entity => $additionalProperty) {
                if (in_array($entity, $entities)) {
                    if (!in_array($property, $additionalProperty)) {
                        EntityRelation::addEntityRelation($entity, $property);
                    }
                } else {
                    if (in_array($property, $additionalProperty)) {
                        EntityRelation::removePropertyFromEntityRelations($entity, $property);
                    }
                }
            }
        } else {
            foreach ($entityRelations as $entity => $additionalProperty) {
                EntityRelation::removePropertyFromEntityRelations($entity, $property);
            }
        }
    }
}