<?php

namespace App\Libs\Backoffice;

use App\Facades\Backoffice\BackendUserService;
use App\Facades\Backoffice\BackofficeService;
use App\Jobs\Backoffice\ProcessSearch;
use App\Libs\Backoffice\Actions\BaseAction;
use App\Libs\Backoffice\Contracts\ExternalField;
use App\Libs\Backoffice\Contracts\ListableField;
use App\Libs\Backoffice\Contracts\SearchableField;
use App\Libs\Backoffice\Exceptions\InvalidConfigurationException;
use App\Libs\Backoffice\Exceptions\InvalidPermissionException;
use App\Libs\Backoffice\Fields\SelectBoxField;
use App\Libs\Backoffice\Fields\TextBoxField;
use App\Libs\Backoffice\FieldCollection;
use App\Models\Backoffice\WebsiteObjectLanguage;
use Closure;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;

class ContentType implements Arrayable, Jsonable
{
    const SHAREABLE_NONE = "none";
    const SHAREABLE_SHARE = "share";
    const SHAREABLE_GLOBAL = "global";

    protected $type;
    protected $group;
    protected $modelType;
    protected $label = "";
    protected $labelSingular = "";
    protected $template = false;
    protected $templates = [];
    protected $hierarchic = false;
    protected $order = false;
    protected $showSlug = false;
    protected $showUri = false;
    protected $hasStatus = true;
    protected $fields;
    protected $actions;
    protected $baseUri = false;
    protected $parent = false;
    protected $search = [];
    protected $showId = false;
    protected $filters;
    protected $hasUri = false;
    protected $isPage = false;
    protected $defaultSort = false;

    public function __construct($config)
    {
        if (empty($config)) {
            throw new InvalidConfigurationException("You must provide a configuration");
        }

        if (is_string($config)) {
            $config = config("backoffice.contentTypes.{$config}");
        }

        if (empty($config) || !is_array($config)) {
            throw new InvalidConfigurationException("You must provide a configuration");
        }

        $this->_initialize($config);
    }

    protected function _initialize($config)
    {
        if (empty($config["type"])) {
            throw new InvalidConfigurationException("The configuration is missing type");
        }

        if (empty($config["model"]) || !class_exists($config["model"])) {
            throw new InvalidConfigurationException("The configuration is missing a valid model");
        }

        if (empty($config["fields"])) {
            throw new InvalidConfigurationException("The configuration is missing fields");
        }

        $backendUser = BackendUserService::getLoggedUser();

        if (!empty($backendUser)) {
            if (!$backendUser->hasPermission("cms.manage")) {
                throw new InvalidPermissionException("You don't have permissions to view this content type");
            }
        }

        $this->modelType = $config["model"];
        $this->type = $config["type"];
        $this->label = trans($config["label"]);
        $this->labelSingular = trans($config["label_singular"]);

        if (empty($config["group"])) {
            $this->group = trans('backend.content');
        } else {
            $this->group = $config["group"];
        }
        if (!empty($config["search"])) {
            $this->search = $config["search"];
        }

        if (!empty($config["isPage"])) {
            $this->isPage = $config["isPage"];
        }

        if (!empty($config["template"])) {
            $this->template = $config["template"];
        }

        if (!empty($config["templates"])) {
            $this->templates = $config["templates"];
        }

        if (!empty($config["hierarchic"])) {
            $this->hierarchic = $config["hierarchic"];
        }

        if (!empty($config["order"])) {
            $this->order = $config["order"];
        }

        if (!empty($config["showSlug"])) {
            $this->showSlug = $config["showSlug"];
        }

        if (!empty($config["showUri"])) {
            $this->showUri = $config["showUri"];
        }

        if (isset($config["hasStatus"])) {
            $this->hasStatus = $config["hasStatus"];
        }

        if (!empty($config["baseUri"])) {
            $this->baseUri = $config["baseUri"];
        }

        if (!empty($config["parent"])) {
            $this->parent = $config["parent"];
        }
        if (!empty($config["show_id"])) {
            $this->showId = $config["show_id"];
        }

        if (!empty($config["filters"])) {
            $this->filters = $config["filters"];
        } else {
            $this->filters = [];
        }

        if (array_key_exists('hasUri', $config)) {
            $this->hasUri = $config["hasUri"];
        }

        if (!empty($config["defaultSort"])) {
            $this->defaultSort = $config["defaultSort"];
        }

        $this->fields = new FieldCollection();
        $this->actions = new ActionCollection();

        if (!empty($config["actions"]) && !empty($backendUser)) {
            foreach ($config["actions"] as $action) {
                $actionType = ucfirst($action);
                $class = "App\\Libs\\Backoffice\\Actions\\{$actionType}Action";
                $class = new $class();
                $this->actions->push(new $class());
            }
        }

        $sectionCount = 0;

        foreach ($config["fields"] as $fieldConfig) {
            if (empty($fieldConfig["type"])) {
                throw new InvalidConfigurationException("There are fields without a type in the configuration");
            }if ($fieldConfig["type"] === 'section') {
                $sectionCount++;
            }
            $fieldType = ucfirst($fieldConfig["type"]);
            $class = "App\\Libs\\Backoffice\\Fields\\{$fieldType}Field";
            $this->fields->push(new $class($fieldConfig,  $this->getModelType()));
        }
        if ($sectionCount % 2) {
            throw new InvalidConfigurationException("There are section fields with invalid matching types");
        }
    }

    public function getType()
    {
        return $this->type;
    }

    public function setType($type)
    {
        $this->type = $type;
    }

    public function getHasUri()
    {
        return $this->hasUri;
    }

    public function setHasUri($hasUri)
    {
        $this->hasUri = $hasUri;
    }

    public function isPage()
    {
        return $this->isPage;
    }

    public function setIsPage($isPage)
    {
        $this->isPage = $isPage;
    }

    public function getModelType()
    {
        return $this->modelType;
    }

    public function setModelType($modelType)
    {
        $this->modelType = $modelType;
    }

    public function getLabel()
    {
        return $this->label;
    }

    public function setLabel($label)
    {
        $this->label = $label;
    }

    public function getSingularLabel()
    {
        return $this->labelSingular;
    }

    public function setSingularLabel($labelSingular)
    {
        $this->labelSingular = $labelSingular;
    }

    public function getFields()
    {
        return $this->fields;
    }

    public function isHierarchic()
    {
        return $this->hierarchic;
    }

    public function setHierarchic($hierarchic = false)
    {
        $this->hierarchic = $hierarchic;
    }

    public function isOrderable()
    {
        return $this->order;
    }

    public function setOrderable($order = false)
    {
        $this->order = $order;
    }

    public function getShowSlug()
    {
        return $this->showSlug;
    }

    public function setShowSlug($showSlug = false)
    {
        $this->showSlug = $showSlug;
    }

    public function getShowUri()
    {
        return $this->showUri;
    }

    public function setHasStatus($hasStatus = true)
    {
        $this->hasStatus = $hasStatus;
    }

    public function getHasStatus()
    {
        return $this->hasStatus;
    }

    public function getShowId()
    {
        return $this->showId;
    }

    public function setShowUri($showUri = false)
    {
        $this->showUri = $showUri;
    }

    public function hasTemplate()
    {
        return $this->template;
    }

    public function setTemplate($template = false)
    {
        $this->template = $template;
    }

    public function getTemplates()
    {
        return $this->templates;
    }

    public function getActions($actionType = null)
    {
        if (empty($actionType)) {
            return $this->actions;
        } else {
            return $this->actions->getActionsByActionType($actionType);
        }
    }

    public function hasActions($actionType = null)
    {
        $actions = $this->getActions($actionType);
        return !$actions->isEmpty();
    }

    public function getGroup()
    {
        return $this->group;
    }

    public function setGroup($group)
    {
        if (empty($group)) {
            $this->group = trans('backend.content');
        } else {
            $this->group = $group;
        }
    }

    public function getBaseUri()
    {
        return $this->baseUri;
    }

    public function setBaseUri($baseUri)
    {
        $this->baseUri = $baseUri;
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function setParent($parent)
    {
        $this->parent = $parent;
    }

    public function getFilters()
    {
        return $this->filters;
    }

    public function setFilters($filters)
    {
        $this->filters = $filters;
    }

    public function isSearchable()
    {
        return $this->search;
    }

    public function getSearch()
    {
        return $this->search;
    }

    public function getSearchFields()
    {
        return array_key_exists('fields', $this->search) ? $this->search['fields'] : null;
    }
    public function getSearchParentRelationships()
    {
        return array_key_exists('parentRelationships', $this->search) ? $this->search['parentRelationships'] : null;
    }
    public function getSearchRelations()
    {
        return array_key_exists('relations', $this->search) ? $this->search['relations'] : null;
    }
    public function getSearchIncludes()
    {
        return array_key_exists('include', $this->search) ? $this->search['include'] : null;
    }
    public function getSearchTitle()
    {
        return array_key_exists('title', $this->search) ? $this->search['title'] : null;
    }

    public function toList($page = null, $itemsPerPage = null, $sort = null, $searchPhrase = null, $filter = null)
    {
        if ($this->isHierarchic()) {
            if (empty($sort) && empty($searchPhrase) && empty($filter)) {
                return $this->_toHierarchicList($page, $itemsPerPage);
            }
        }

        return $this->_toFlatList($page, $itemsPerPage, $sort, $searchPhrase, $filter);
    }

    public function toStructuredList()
    {
        $items = $this->_toHierarchicList(null, null);

        $list = array();

        foreach ($items as $item) {
            $list[$item->id] = $item;
        }
        return $this->_structureList($list);
    }

    private function _structureList($listItems)
    {
        $grouped = collect($listItems)->groupBy(function($item) {
            return $item->getActiveWebsiteEntry()->parent_id;
        });

        return $this->_buildTree($grouped);
    }

    private function _buildTree($grouped, $parentId = null)
    {
        $tree = [];
        foreach ($grouped->get($parentId, []) as $item) {
            $item->children = $this->_buildTree($grouped, $item->website_object_id);
            $tree[] = $item;
        }
        return $tree;
    }

    protected function _toFlatList($page, $itemsPerPage, $sort, $searchPhrase, $requestFilter = null)
    {
        Paginator::currentPageResolver(function () use ($page) {
            return $page;
        });

        $fields = $this->fields->getListableFields();
        $hasLanguage = !$fields->getMultiLanguageFields()->isEmpty();

        $sortColumn = null;
        $orderField = null;
        $sortOrder = null;
        if (!empty($sort)) {
            $sortColumn = $sort['key'];
            $sortOrder = $sort['order'];
        } elseif ($this->defaultSort) {
            $sortColumn = $this->defaultSort['field'];
            $sortOrder = $this->defaultSort['direction'];
        } else {
            $sortColumn = 'website_object_id';
            $sortOrder = 'desc';
        }

        if ($sortColumn != "website_object_id" && $sortColumn != "slug" && $sortColumn != "uri" && $sortColumn != "status" && $sortColumn != "position") {
            $orderField = $fields->find($sortColumn);

            if (empty($orderField)) {
                throw new InvalidConfigurationException("The order field is not part of this content type list fields");
            }
        }

        $modelType = $this->modelType;

        $queryBuilder = $modelType::query();
        $model = $queryBuilder->getModel();

        $websiteEntryRelationship = $model->websites();
        $websiteEntryModel = $websiteEntryRelationship->getRelated();
        $websiteEntryFK = $websiteEntryRelationship->getQualifiedForeignKeyName();

        $queryBuilder->join($websiteEntryModel->getTable(),
            function ($join) use ($model, $websiteEntryFK, $websiteEntryRelationship, $modelType) {
                $join->on($model->getQualifiedKeyName(), "=", $websiteEntryFK)
                    ->where($websiteEntryRelationship->getMorphType(), "=", $modelType);
            });

        $queryBuilder->join('website_objects_lang',
            function ($join) {
                $join->on('website_objects.website_object_id', "=", 'website_objects_lang.website_object_id')
                    ->where('website_objects_lang.wo_language_id', "=", LaravelLocalization::getCurrentLocale());
            });

        if ($hasLanguage) {
            $languageRelationship = $model->languages();
            $languageModel = $languageRelationship->getRelated();
            $languageFK = $languageRelationship->getQualifiedForeignKeyName();
            $queryBuilder->join($languageModel->getTable(), $model->getQualifiedKeyName(), "=", $languageFK);
            $queryBuilder->where("{$languageModel->getTable()}.language_id", "=",
                LaravelLocalization::getCurrentLocale());
        }
        if (!empty($sortColumn)) {
            if (!empty($orderField)) {
                $orderField->buildOrder($queryBuilder, $sortOrder);
            } else {
                $queryBuilder->orderBy("website_objects_lang.{$sortColumn}", $sortOrder);
            }
        }

        foreach ($this->getFilters() as $filter) {
            if (is_null($filter["value"])) {
                $queryBuilder->whereNull($filter["field"]);
            } else {
                $queryBuilder->where($filter["field"], $filter["value"]);
            }
        }

        if (!empty($requestFilter)) {
            if (!empty($requestFilter['status'])) {
                $queryBuilder->whereIn('website_objects_lang.status', $requestFilter['status']);
            }

            if (!empty($requestFilter['created_at'])) {
                $queryBuilder->whereDate("{$model->getTable()}.created_at", $requestFilter['created_at']);
            }
        }

        $queryBuilder->addSelect($model->getQualifiedKeyName());

        $queryBuilder->addSelect("website_objects_lang.status");

        if ($this->getShowUri()) {
            $queryBuilder->addSelect("website_objects_lang.uri");
        }

        if ($this->getShowSlug()) {
            $queryBuilder->addSelect("website_objects_lang.slug");
        }

        foreach ($fields as $field) {
            if ($field instanceof ListableField) {
                $field->buildSelect($queryBuilder);
            }
        }
        if (!empty($searchPhrase)) {
            $queryBuilder->where(function ($query) use ($fields, $searchPhrase) {
                foreach ($fields as $field) {
                    if ($field instanceof ListableField) {
                        $field->buildWhere($query, $searchPhrase);
                    }
                }
            });
            if (is_numeric($searchPhrase)) {
                $table = $queryBuilder->getModel()->getTable();
                $langTable = $queryBuilder->getModel()->languages()->getRelated()->getTable();
                $queryBuilder->orWhere("{$table}.id", $searchPhrase * 1);
                $queryBuilder->where("$langTable.language_id", LaravelLocalization::getCurrentLocale());
            }
        }

        if (empty($page) || empty($itemsPerPage)) {
            $rows = $queryBuilder->get();
            return $rows;
        } else {
            $paginator = $queryBuilder->paginate($itemsPerPage);

            return array(
                "total" => $paginator->total(),
                "current" => $paginator->currentPage(),
                "rowCount" => $itemsPerPage,
                "rows" => $paginator->getCollection()
            );
        }
    }

    protected function _toHierarchicList($page, $itemsPerPage)
    {
        $fields = $this->fields->getListableFields();

        if (!$this->isOrderable()) {
            $hasLanguage = true;
        } else {
            $hasLanguage = !$fields->getMultiLanguageFields()->isEmpty();
        }

        $modelType = $this->modelType;

        $queryBuilder = $modelType::query();
        $model = $queryBuilder->getModel();

        $websiteEntryRelationship = $model->websites();


        $websiteEntryModel = $websiteEntryRelationship->getRelated();
        $websiteEntryFK = $websiteEntryRelationship->getQualifiedForeignKeyName();


        $queryBuilder->join($websiteEntryModel->getTable(),
            function ($join) use ($model, $websiteEntryFK, $websiteEntryRelationship, $modelType) {
                $join->on($model->getQualifiedKeyName(), "=", $websiteEntryFK)
                    ->where($websiteEntryRelationship->getMorphType(), "=", $modelType);
            });

        if ($hasLanguage) {
            $languageRelationship = $model->languages();
            $languageModel = $languageRelationship->getRelated();
            $languageFK = $languageRelationship->getQualifiedForeignKeyName();
            $queryBuilder->join($languageModel->getTable(), $model->getQualifiedKeyName(), "=", $languageFK);
            $queryBuilder->where("{$languageModel->getTable()}.language_id", "=",
                LaravelLocalization::getCurrentLocale());
        }

        $queryBuilder->orderBy("{$websiteEntryModel->getTable()}.parent_id", "asc");

        if ($this->isOrderable()) {
            $queryBuilder->orderBy("{$websiteEntryModel->getTable()}.position", "asc");
        } else {
            $queryBuilder->orderBy("{$languageModel->getTable()}.title", "asc");
        }

        $queryBuilder->addSelect($model->getQualifiedKeyName());
        $queryBuilder->addSelect($websiteEntryModel->getQualifiedKeyName());
        $queryBuilder->addSelect($websiteEntryModel->getTable().".parent_id");
        $queryBuilder->addSelect($websiteEntryModel->getTable().".template");
        //$queryBuilder->addSelect($websiteEntryModel->getTable().".status");

        $wolanguageRelationship = $websiteEntryModel->languages();
        $woLanguageModel = $wolanguageRelationship->getRelated();
        $woLanguageFK = $wolanguageRelationship->getQualifiedForeignKeyName();
        $queryBuilder->join($woLanguageModel->getTable(), $websiteEntryModel->getQualifiedKeyName(), "=", $woLanguageFK);
        $queryBuilder->where("{$woLanguageModel->getTable()}.wo_language_id", "=",
            LaravelLocalization::getCurrentLocale());

        if ($this->getShowUri()) {
            $queryBuilder->addSelect($woLanguageModel->getTable().".uri");
        }

        if ($this->getShowSlug()) {
            $queryBuilder->addSelect($woLanguageModel->getTable().".slug");
        }

        foreach ($fields as $field) {
            if ($field instanceof ListableField) {
                $field->buildSelect($queryBuilder);
            }
        }

        $rows = $queryBuilder->get();

        $rows = new EloquentCollection($this->_buildHierarchicList($rows));

        if (empty($page) || empty($itemsPerPage)) {
            return $rows;
        } else {
            $offset = ($page - 1) * $itemsPerPage;

            return array(
                "total" => $rows->count(),
                "current" => (int) $page,
                "rowCount" => (int) $itemsPerPage,
                "rows" => $rows->slice($offset, $itemsPerPage)->values()
            );
        }

    }

    protected function _buildHierarchicList(
        EloquentCollection $oriItems,
        array $outItems = array(),
        $parent_id = null,
        $depth = 0
    ) {

        foreach ($oriItems as $item) {
            if ($item->getActiveWebsiteEntry()->parent_id == $parent_id) {
                $titlePrefix = "";
                for ($i = 0; $i < $depth; $i++) {
                    $titlePrefix .= "— ";
                }
                $item->clean_title = $item->title;
                $item->title = $titlePrefix.$item->title;
                array_push($outItems, $item);
                $outItems = $this->_buildHierarchicList($oriItems, $outItems, $item->getActiveWebsiteEntry()->id,
                    $depth + 1);
            } elseif ($item->getActiveWebsiteEntry()->parent_id > $parent_id) {
                break;
            }
        }

        return $outItems;
    }

    public function hasFormFields()
    {
        $fields = $this->fields->getMainFormFields();
        return !$fields->isEmpty();
    }
/*
    public function toForm($model, $placement = "main", $isPreview = FALSE)
    {
        $fields = $this->fields->getFieldsByPlacement($placement);
        $form = "";
        $enabled = $this->userHasPermission() && !$isPreview;
        foreach ($fields as $field) {
            if ($field instanceOf ExternalField) {
                continue;
            }
            $parent = $field->getParent();
            $hidden = false;
            if (!empty($parent)) {
                $value = $this->getFieldValue($parent["name"], $model);
                if (!in_array($value, $parent["values"])) {
                    $hidden = true;
                }
            }
            $form .= $field->toForm($model, $enabled, $hidden);
        }
        return $form;
    }
*/
    public function getData($model, $placement = "main", $isPreview = FALSE)
    {
        $fields = $this->fields;

        $enabled = $this->userHasPermission() && !$isPreview;
        $sidebarFields = [];
        $sections = [];
        foreach ($fields as $field) {
            if ($field instanceOf ExternalField) {
                continue;
            }
            $placement = $field->getPlacement();

            if ($placement == 'sidebar') {
                $sidebarFields[] = $field->getData($model, $enabled);
            }

            if (!array_key_exists($placement, $sections)) {
                $sections[$placement] = [
                    'label' => trans('content_types.' . $placement),
                    'fields' => []
                ];
            }
            $sections[$placement]['fields'][] = $field->getData($model, $enabled);
        }

        return [
            'type' => $this->getType(),
            'label' => $this->getSingularLabel(),
            'localeErrors' => $this->getErrorLocales(),
            'hasFields' => $this->hasFormFields(),
            'enabled' => $enabled,
            'fieldSections' => $sections,
            'sidebarFields' => $sidebarFields,
            'websiteData' => $this->getWebsiteData($model, $isPreview = FALSE)
        ];
    }

    public function toExternalForm($model, $placement = "main", $isPreview = FALSE)
    {
        $fields = $this->fields->getExternalFields($placement);
        $form = "";
        $enabled = $this->userHasPermission() && !$isPreview;
        foreach ($fields as $field) {
            $parent = $field->getParent();
            $hidden = false;
            if (!empty($parent)) {
                $value = $this->getFieldValue($parent["name"], $model);
                if (!in_array($value, $parent["values"])) {
                    $hidden = true;
                }
            }
            $form .= $field->toForm($model, $enabled, $hidden);
        }
        return $form;
    }

    public function getFieldValue($fieldName, $model)
    {
        $field = $this->fields->find($fieldName);
        if (!is_null($field)) {
            return $field->getCurrentValue($model);
        } else {
            //this if the field is the slug or template
            return $model->$fieldName;
        }
    }

    public function getWebsiteData($model, $isPreview = FALSE)
    {
        if (!$this->isPage) {
            return [
                "fields" => [],
            ];
        }

        $languages = LaravelLocalization::getSupportedLanguagesKeys();
        $enabled = $this->userHasPermission() && !$isPreview;
        $fields = [];

        $websiteObject = $model->getActiveWebsiteEntry();

        $slug = new TextBoxField([
            'name' => 'slug',
            'type' => 'TextBox',
            'label' => 'Slug',
            'multiLanguage' => true,
            'woMultilang' => true
        ]);
        $slugInput = request()->old("slug");
        $hidden = false;
        if (!$model->exists && empty($slugInput)) {
            $hidden = true;
        }

        $fields[] = $slug->getData($websiteObject, $enabled, $hidden);

        $status = new SelectBoxField(array(
            'name' => 'status',
            'type' => 'SelectBox',
            'label' => trans('backend.status'),
            'multiLanguage' => true,
            'list' => [
                'draft' => trans('backend.draft'),
                'published' => trans('backend.published')
            ],
            'defaultValue' => 'published'
        ), $this->getModelType());

        $fields[] = $status->getData($websiteObject, $enabled, !$this->hasStatus);

        if ($this->template) {
            $templatesSelectList = array();
            $templates = array();

            if (!empty($this->templates)) {
                $templates = $this->templates;
            }

            foreach ($templates as $template) {
                $templatesSelectList[$template['id']] = $template['name'];
            }

            $defaultValue = "";
            /*if (!empty($templates)) {
                $defaultValue = head($templates)['id'];
            }*/

            $templateSelect = new SelectBoxField(array(
                'name' => 'template',
                'type' => 'SelectBox',
                'label' => trans('backend.template'),
                'list' => $templatesSelectList,
                'defaultValue' => $defaultValue
            ), $this->getModelType());
            $fields[] =  $templateSelect->getData($websiteObject, $enabled);
        }

        /*
        if ($model->exists && ($this->baseUri || $this->hasTemplate()) && $enabled) {
            $form .= '<a href="#" data-uri="'.$model->uri
                .'" target="_blank" class="preview-page btn btn-primary pull-right">Preview</a><div class="clearfix"></div>';
        }
        */

        return [
            "fields" => $fields,
        ];
    }

    public function getValidation($model = null)
    {
        $rules = array();
        $values = array();
        $labels = array();
        $request = request(null);

        foreach ($this->fields as $field) {
            $validation = $field->getValidationDataRules($model);
            if (is_null($validation)) {
                continue;
            }
            $validation['values'][$field->getName()] = $field->getValidationDataValues(!$model || !$model->exists);

            $rules = array_merge($rules, $validation["rules"]);
            $values = array_merge($values, $validation["values"]);
            $labels = array_merge($labels, $validation["labels"]);
        }

        $languages = array_keys(LaravelLocalization::getSupportedLocales());
        if ($this->isPage) {
            $rules['status'] = "required|array";
            $rules['status.*'] = "|in:draft,published";

            $rules['slug'] = "array";

            $rules['slug.*'] = [function (string $attribute, mixed $value, Closure $fail) use ($model) {
                $lang = explode('.', $attribute)[1];
                if (!$model->exists || !$value) {
                    return;
                }

                $websiteObject = $model->getActiveWebsiteEntry();
                $websiteObjectLang = $websiteObject->languages->findByLocale($lang);
                $uri = BackofficeService::getUriLang($value, $lang, $this, $websiteObject);

                if ($model->exists && $websiteObjectLang->slug == $value) {
                    return;
                }
                if (WebsiteObjectLanguage::where('uri', $uri)->where('wo_language_id', $lang)->count()) {
                    $fail("The slug is already taken.");
                }
            }];
        }

        if ($this->template) {
            $templates = $this->getTemplates();
            $availTemplates = implode(',', array_keys($templates));
            $rules['template'] = "required|in:".$availTemplates;
        }

        $values['slug'] = $request->input("slug");
        $values['status'] = $request->input("status");
        $values['template'] = $request->input("template");
        $labels['slug'] = "slug";
        $labels['status'] = "status";
        $labels['template'] = "template";

        return array("rules" => $rules, "values" => $values, "labels" => $labels);
    }

    public function getErrorLocales()
    {
        $errorLocales = array();
        $errors = Context::get('errors');
        if (empty($errors)) {
            return $errorLocales;
        }

        $locales = LaravelLocalization::getSupportedLocales();

        foreach ($locales as $locale => $localeData) {
            $errorLanguage = Arr::where($errors->toArray(), function ($value, $key) use ($locale) {
                return Str::endsWith($key, ".".$locale) || Str::contains($key, ".{$locale}.");
            });

            if (!empty($errorLanguage)) {
                $errorLocales[] = $locale;
            }
        }
        return $errorLocales;

    }

    /*
    public function getScripts(){
        $scripts = array(
            'genericForm' => path_asset('path.backoffice.js_path') . '/view/backend-generic-form.js',
            'langPicker' => path_asset('path.backoffice.js_path') . '/view/backend-lang-tab-picker.js'
        );

        foreach($this->fields as $field){
            $script = $field->getScript();
            if(!is_null($script)){
                $scripts = array_merge($scripts, $script);
            }
        }

        return $scripts;
    }
    */

    public function hasExternalFields()
    {
        $externalFields = $this->fields->getExternalFields();
        if ($externalFields->isEmpty()) {
            return false;
        } else {
            return true;
        }
    }

    public function userHasPermission()
    {
        $user = BackendUserService::getLoggedUser();
        if (empty($user)) {
            return false;
        }

        return $user->hasPermission("cms.manage");
    }

    public function getSearchStructure($model)
    {
        if (!$this->isSearchable()) {
            return array();
        }

        $search = array();
        $searchData = $this->getSearch();

        $searchLevels = array("primary", "secondary");


        foreach ($searchLevels as $level) {
            if (!empty($searchData[$level])) {
                $searchFields = $this->fields->getFieldsByNames($searchData[$level]);

                foreach ($searchFields as $field) {
                    if (!($field instanceOf SearchableField)) {
                        continue;
                    }

                    $fieldSearch = $field->getSearchStructure($model);
                    if (empty($fieldSearch)) {
                        continue;
                    }

                    foreach ($fieldSearch as $languageKey => $searchValue) {
                        if (!isset($search[$languageKey])) {
                            $search[$languageKey] = array();
                            $search[$languageKey]["content_type"] = $this->getType();
                            $search[$languageKey]["group_label"] = trans("backend.{$this->getType()}_plural");
                        }

                        if (!isset($search[$languageKey]["{$level}_search"])) {
                            $search[$languageKey]["{$level}_search"] = "";
                        }

                        $search[$languageKey]["{$level}_search"] = $search[$languageKey]["{$level}_search"]." ".$searchValue;
                    }
                }
            }
        }

        if (!empty($searchData["display"])) {
            foreach ($searchData["display"] as $displayType => $fieldName) {
                $field = $this->fields->find($fieldName);
                if (empty($field) || !($field instanceOf SearchableField)) {
                    continue;
                }

                $fieldSearch = $field->getSearchStructure($model, true);
                if (empty($fieldSearch)) {
                    continue;
                }

                foreach ($fieldSearch as $languageKey => $searchValue) {
                    if (!isset($search[$languageKey])) {
                        $search[$languageKey] = array();
                        $search[$languageKey]["content_type"] = $this->getType();
                        $search[$languageKey]["group_label"] = trans("backend.{$this->getType()}_plural");
                    }

                    $search[$languageKey][$displayType] = $searchValue;
                }

            }
        }


        if (empty($searchData["uri"])) {
            $websiteObject = $model->getActiveWebsiteEntry();

            if (!empty($websiteObject)) {
                foreach ($search as $languageKey => $searchValue) {
                    $woLang = $websiteObject->languages->findByLocale($languageKey);
                    if ($woLang && $woLang->uri) {
                        $search[$languageKey]["uri"] = $woLang->uri;
                    }
                }
            }
        } else {
            foreach ($search as $languageKey => $searchValue) {
                if (is_array($searchData["uri"])) {
                    $searchUri = $searchData["uri"][$languageKey];
                } else {
                    $searchUri = $searchData["uri"];
                }

                if (Str::contains($searchUri, "{type}") && isset($model->type)) {
                    if (isset($this->baseUri)) {
                        $baseUri = $this->baseUri[$model->type];
                        if (is_array($baseUri)) {
                            $searchUri = str_replace("{type}", $baseUri[$languageKey], $searchUri);
                        } else {
                            $searchUri = str_replace("{type}", $baseUri, $searchUri);
                        }
                    } else {
                        $searchUri = str_replace("{type}", $model->type, $searchUri);
                    }
                }

                if (Str::contains($searchUri, "{slug}")) {
                    $websiteObject = $model->getActiveWebsiteEntry();

                    if (!empty($websiteObject)) {
                        $woLang = $websiteObject->languages->findByLocale($languageKey);
                        $search[$languageKey]["uri"] = str_replace("{slug}", $woLang->slug, $searchUri);
                    }
                } else {
                    $search[$languageKey]["uri"] = $searchUri;
                }
            }
        }
        return $search;
    }

    public function autoComplete($searchTerm)
    {
        $modelType = $this->modelType;
        $model = new $modelType();
        $query = $model->full()->where("title", 'like', "%".$searchTerm."%")
            ->select("id", "title", "id as object_id")
            ->orderBy("title", "asc")
            ->limit(10);
        $filters = $this->getFilters();

        foreach ($this->getFilters() as $filter) {
            if (is_null($filter["value"])) {
                $query->whereNull($filter["field"]);
            } else {
                $query->where($filter["field"], $filter["value"]);
            }
        }
        return $query->get();
    }

    public function toArray($onlyListable = false)
    {
        $array = array(
            'type' => $this->getType(),
            'label' => $this->getLabel(),
            'labelSingular' => $this->getSingularLabel(),
            'hierarchic' => $this->isHierarchic(),
            'order' => $this->isOrderable(),
            'isPage' => $this->isPage(),
            'templates' => $this->getTemplates(),
            'isPage' => $this->isPage,
            'actions' => array(
                "grid" => $this->actions->getActionsByActionType(BaseAction::TYPE_GRID)->toArray(),
                "row" => $this->actions->getActionsByActionType(BaseAction::TYPE_ROW)->toArray()
            ),
            'fields' => array()
        );


        if ($onlyListable) {
            $fields = $this->fields->getListableFields();
        } else {
            $fields = $this->fields;
        }

        $array["fields"] = $fields->toArray();

        return $array;
    }

    public function toJson($options = 0)
    {
        return json_encode($this->toArray(), $options);
    }

    public function regenerateSearchIndex()
    {
        if (empty($this->getSearch())) {
            return;
        }
        $modelType = $this->modelType;
        $model = new $modelType();

        $query = $model::full()->select('id');

        $query->chunk(100, function ($items) {
            foreach ($items as $item) {
                ProcessSearch::dispatch($this, $item);
            }
        });
    }
}
