<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\AdminContentAutoComplete;
use App\Http\Requests\AdminExportContentListRequest;
use App\Http\Requests\AdminShareLinkRequest;
use App\Jobs\ProcessSearch;
use App\Libs\Backoffice\Generic\ContentType;
use App\Libs\Backoffice\Generic\UriHelper;
use App\Libs\Contracts\Backoffice\ExternalField;
use App\Libs\Contracts\Backoffice\SavableField;
use App\Libs\Events\ContentTypeSaved;
use App\Libs\Events\ContentTypeDeleted;
use App\Libs\Facades\ContentTypes;
use App\Libs\Facades\Localization;
use App\Libs\Facades\RequestContext;
use Block;
use Carbon\Carbon;
use ContentVersion;
use Exception;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ViewErrorBag;
use ShareLink;
use Silber\PageCache\Cache;
use Throwable;
use Website;
use WebsiteObject;
use WebsiteObjectLanguage;

class ContentController extends Controller
{
    public function getIndex($type)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        $user = Auth::guard('admin')->user();
        Gate::forUser($user)->authorize('admin-has-permission', "backend.content.{$type}.view");
        return view('admin.generic.pages.list', array("contentType" => $contentType));
    }

    public function postList($type)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        $user = Auth::guard('admin')->user();
        Gate::forUser($user)->authorize('admin-has-permission', "backend.content.{$type}.view");

        $page = request()->get("current");
        $sort = request()->get("sort");
        $search = request()->get("searchPhrase");
        $rowCount = request()->get("rowCount");
        $subtype = request()->get("subtype");

        $list = $contentType->toList($page, $rowCount, $sort, $search, $subtype);
        return response()->json($list);
    }

    public function postCheckSlug()
    {
        $originSlug = request()->get("slug");
        $langId = request()->get("lang");

        if (empty($originSlug) || empty($langId)) {
            return response()->json(array(
                "error" => "bad_syntax",
                "description" => "The request is missing the slug"
            ), 400);
        }

        $slug = UriHelper::generateSlug($originSlug, null, $langId);

        if ($slug === false) {
            return response()->json(array(
                "error" => "invalid",
                "description" => "Impossible to generate this slug"
            ), 400);
        } else {
            return response()->json(array("slug" => $slug));
        }
    }

    public function getFormTemplate($type, $parentId)
    {
        if (!is_numeric($parentId)) {
            abort(404);
        }

        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        if (!$contentType->userHasPermission("view")) {
            abort(403, trans("http_status.403"));
        }

        $parentData = $contentType->getParent();

        if (empty($parentData)) {
            abort(404);
        }
        $modelType = $contentType->getModelType();
        $model = $modelType::where($parentData["field"], $parentId)->first();
        $message = null;
        if (empty($model)) {
            $message = trans("backend.save_success_redirect_config");
            $model = $this->_insertFormTemplate($contentType, $parentId);
        }
        $url = "/admin/content/form/{$type}/{$model->id}/{$parentId}";

        return redirect()->to($url)->withMessage($message);
    }

    private function _insertFormTemplate($contentType, $parentId)
    {
        $loggedUser = Auth::guard('admin')->user();
        $modelType = $contentType->getModelType();
        $model = new $modelType;

        $parentData = $contentType->getParent();
        $parentContentType = ContentTypes::find($parentData["contentType"]);
        $parentModelType = $parentContentType->getModelType();
        $parentModel = $parentModelType::find($parentId);
        $fkName = $parentModel->getForeignKey();

        if (empty($parentModel)) {
            abort(404);
        }
        DB::beginTransaction();

        try {
            $model->$fkName = $parentId;
            $model->backend_user_id = $loggedUser->id;
            $model->save();

            $languageModels = $model->languages;
            $languageModelType = $model->languages()->getRelated();

            foreach ($parentModel->languages as $parentLangModel) {
                $languageModel = new $languageModelType;
                $languageModel->language_id = $parentLangModel->language_id;
                $languageModel->title = $parentLangModel->title;
                $languageModels->add($languageModel);
            }

            $model->languages()->saveMany($languageModels->all());

            $websiteObjects = $model->websites;
            $parentWebsiteObject = $parentModel->websites->findByWebsite(Localization::getWebsite()->id);

            $websiteObject = new WebsiteObject;
            $websiteObject->website_id = Localization::getWebsite()->id;
            $websiteObject->content_type = $contentType->getType();
            $slug = $parentWebsiteObject->slug."-conf-".$parentWebsiteObject->id;
            $websiteObject->slug = $slug;
            $websiteObject->status = $parentWebsiteObject->status;
            $websiteObjects->add($websiteObject);

            $model->websites()->saveMany($websiteObjects->all());

            foreach ($parentModel->languages as $langModel) {
                $woLang = new WebsiteObjectLanguage ();
                $woLang->website_object_id = $websiteObject->id;
                $woLang->wo_language_id = $langModel->language_id;
                $woLang->lang_slug = $slug;
                $woLang->lang_status = $parentWebsiteObject->status;
                $woLang->lang_uri = null;
                $woLang->wo_website_id = $websiteObject->website_id;

                $woLang->save();
            }

            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            Log::error($e);
            throw($e);
        }

        return $model;
    }

    public function postAutoComplete(AdminContentAutoComplete $request, $baseContentype = null, $field = null)
    {
        if ($baseContentype) {
            if ($baseContentype == 'event_item') {
                $baseContentype = 'event';
            }

            $contentTypeConfig = config('backoffice.generic.' . $baseContentype);
            if (!$contentTypeConfig) {
                return response()->json(['error' => 'content type not found'], 400);
            }

            $fieldConfig = array_filter($contentTypeConfig['fields'], function($fieldConfig) use ($field) {
                return $fieldConfig['name'] === $field;
            });
            $fieldConfig = array_pop($fieldConfig);

            if ($fieldConfig['type'] === 'link') {
                $objectTypes = \App\Libs\Backoffice\Generic\Fields\LinkField::OBJECT_TYPES;
            } else {
                if (empty($fieldConfig['objectTypes'])) {
                    return response()->json(['error' => 'field or object types config not found'], 400);
                }
                $objectTypes = $fieldConfig['objectTypes'];
            }
        } else {
            $objectTypes = \App\Libs\Backoffice\Generic\Fields\LinkField::OBJECT_TYPES;
        }

        $data = $request->validated();
        $searchTerm = urldecode($data['searchTerm']);

        if (!empty($data['objectType']) && in_array($data['objectType'], $objectTypes)) {
            $objectTypes = [$data['objectType']];
        }

        $mergedResults = [];
        foreach ($objectTypes as $objectType) {
            $typeLocation = $objectType == 'event_item' ? 'event' : $objectType;
            $contentType = config('backoffice.generic.' . $typeLocation);
            $model = $objectType === 'page' ? 'Entry' : $contentType['model'];
            $contentModel = new $model;
            $langTable = $contentModel->languages()->getRelated()->getTable();


            if ($objectType === 'page') {
                $fk = $langTable . '.entry_id';
            } else if ($objectType === 'event') {
                $fk = $langTable . '.event_item_id';
            } else {
                $fk = $langTable . '.' . $objectType . '_id';
            }

            if ($objectType === 'contact') {
                $titleField = 'name';
            } else {
                $titleField = 'title';
            }

            $query = \DB::table('website_objects')
                ->selectRaw("$fk as id, CONCAT($titleField, ' (" . $objectType . ")') as title, website_objects.website_object_id as object_id, website_objects.content_type as type, website_objects.status as status")
                ->where("content_type", $contentType['type'])
                ->where("website_id", 1)
                ->whereNull('website_objects.deleted_at');

            $query->join($langTable, $fk, 'website_objects.object_id')
                ->where('language_id', 'en');

            if ($objectType === 'project' && is_numeric($searchTerm)) {
                $query->join('projects', 'projects.id', 'website_objects.object_id')
                    ->where('projects.spg_id', $searchTerm);
            } else if ($objectType === 'contact') {
                $query->join('contacts', 'contacts.id', 'website_objects.object_id')
                    ->where("name", 'like', "%" . $searchTerm . "%");
            } else {
                $query->where("title", 'like', "%" . $searchTerm . "%");
            }

            $results = $query->limit(sizeof($objectTypes) === 1 ? 19 : 5)->get();
            $mergedResults = array_merge($mergedResults, $results->toArray());
        }

        foreach ($mergedResults as $result) {
            $wols = WebsiteObjectLanguage::where('website_object_id', $result->object_id)
                ->get();
            $langStatus = [];
            $wols->each(function ($wol) use (&$langStatus) {
                $langStatus[$wol->wo_language_id] = $wol->lang_status;
            });
            $result->lang_status = $langStatus;
        }

        return response()->json($mergedResults, 200);
    }

    public function postAutoCompleteOld(AdminContentAutoComplete $request, $type)

    {
        $type = 'block';
        $contentType = ContentTypes::find($type);
        $data = $request->validated();

        $results = $contentType->autoComplete($data['searchTerm']);

        return response()->json($results, 200);
    }

    public function getForm($type, $id = false, $parentId = false, $parentContentType = false, $parentFieldName = false)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        if (!$contentType->userHasPermission("view")) {
            abort(403, trans("http_status.403"));
        }

        $versionId = request()->get('v', null);

        $parentData = $contentType->getParent();

        if ($parentContentType && $parentFieldName) {
            $parentType = ContentTypes::find($parentContentType);
            $parentField = $parentType->getFields()->find($parentFieldName);
            if (!$parentField || $parentField->getObjectType() != $type) {
                abort(404);
            }

            $parentData = array(
                'field' => $parentFieldName,
                'contentType' => $parentContentType
            );
        }

        $modelType = $contentType->getModelType();

        if (!empty($id)) {
            if (!is_numeric($id)) {
                abort(404);
            }

            $model = $modelType::find($id);

            if (empty($model)) {
                abort(404);
            }

        } else {
            if (!$contentType->userHasPermission("create")) {
                abort(403, trans("http_status.403"));
            }

            $modelType = $contentType->getModelType();
            $model = new $modelType;
        }

        if (!$model->exists && (!empty($parentId) && empty($parentData)) ||
            (empty($parentId) && !empty($parentData))) {
            abort(400, trans("http_status.400"));
        }
        $version = null;
        if ($versionId) {
            $version = ContentVersion::where('object_type', $modelType)
                ->where('id', $versionId)
                ->first();

            if (!$version) {
                abort(404);
            }
            $contentType->loadVersion($model, $version);
        }
        RequestContext::set('generic_form_timestamp', time() . '');
        if (request()->ajax()) {
            return view('admin/generic/components/form',
                array(
                    "model" => $model,
                    "contentType" => $contentType,
                    "parentId" => $parentId,
                    "version" => $version
                ));
        } else {
            return view('admin/generic/pages/form',
                array(
                    "model" => $model,
                    "contentType" => $contentType,
                    "parentId" => $parentId,
                    "version" => $version
                ));
        }
    }

    /**
     * Util to reconstruct all uris for a given content type
     *
     * @param  mixed  $type
     */
    public function getUpdateUris($type)
    {
        $contentType = ContentTypes::find($type);

        $website = Localization::getWebsite();

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        if (!$contentType->userHasPermission("create")) {
            abort(403, trans("http_status.403"));
        }

        if (!isset($contentType->getBaseUri()[$website->id])) {
            abort(500, "No base URI configured for this content type");
        }

        $modelType = $contentType->getModelType();
        $models = $modelType::full()->get();

        foreach ($models as $model) {
            $websiteObjects = $model->websites;
            $websiteObject = $websiteObjects->findByWebsite($website->id);
            UriHelper::updateUri($websiteObject, $model, $contentType);
        }

        echo 'Success!';
    }

    public function postForm(
        $type,
        $id = false,
        $parentId = false,
        $parentContentType = false,
        $parentFieldName = false
    ) {
        $contentType = ContentTypes::find($type);
        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404, trans("http_status.404"));
        }

        if (!$contentType->userHasPermission("create")) {
            abort(403, trans("http_status.403"));
        }

        $loggedUser = Auth::guard('admin')->user();
        if (!empty($id)) {
            if (!is_numeric($id)) {
                abort(404);
            }

            $modelType = $contentType->getModelType();
            $model = $modelType::find($id);

            if (empty($model)) {
                abort(404);
            }
        } else {
            $modelType = $contentType->getModelType();
            $model = new $modelType;
        }

        $parentData = $contentType->getParent();
        $hasPivot = false;

        if ($parentContentType && $parentFieldName) {
            $parentType = ContentTypes::find($parentContentType);
            $parentField = $parentType->getFields()->find($parentFieldName);
            if (!$parentField || $parentField->getObjectType() != $type) {
                abort(404);
            }

            $parentData = array(
                'field' => $parentFieldName,
                'contentType' => $parentContentType
            );
            $hasPivot = true;
        }

        if (!$model->exists && (!empty($parentId) && empty($parentData)) ||
            (empty($parentId) && !empty($parentData))) {
            abort(400, trans("http_status.400"));
        }


        $validation = $contentType->getValidation(!$model->exists);

        $validator = Validator::make(
            $validation["values"],
            $validation["rules"]

        );

        $validator->setAttributeNames($validation["labels"]);

        $languages = Localization::getSupportedLanguages();

        foreach ($languages as $lang) {
            $originSlug = $validation["values"]["lang_slug"][$lang->id];
            if ($model->exists && $model->website_object_id) {
                $woLang = WebsiteObjectLanguage::where('website_object_id', $model->website_object_id)
                    ->where('wo_language_id', $lang->id)
                    ->first();
                if ($woLang && $woLang->lang_slug == $originSlug) {
                    continue;
                }
            }
            $slug = UriHelper::generateSlug($originSlug, null, $lang->id);
            $validation["values"]["lang_slug"][$lang->id] = ($slug ? $slug : '');
        }

        $version = null;
        $versionId = request()->get('v', null);
        if ($versionId) {
            $version = ContentVersion::where('object_type', $modelType)
                ->where('id', $versionId)
                ->first();
        }

        if ($validator->fails()) {
            $errors = $validator->errors();
            request()->flash();
            RequestContext::set("errors", $errors);
            view()->share("errors", (new ViewErrorBag)->put('default', $errors));

            if (request()->ajax()) {
                return view('admin/generic/components/form',
                    array(
                        "model" => $model,
                        "contentType" => $contentType,
                        "parentId" => $parentId,
                        "version" => $version
                    ));
            } else {
                return view('admin/generic/pages/form',
                    array(
                        "model" => $model,
                        "contentType" => $contentType,
                        "parentId" => $parentId,
                        "version" => $version
                    ));
            }
        }

        if (!empty($parentData) && !$model->exists && !$hasPivot) {
            $parentField = $parentData["field"];
            $model->$parentField = $parentId;
        }

        $modelFields = $contentType->getFields()->getSingleLanguageFields();

        foreach ($modelFields as $field) {
            if ($field->isRelationField() || $field instanceof ExternalField) {
                continue;
            }
            $fieldName = $field->getName();

            if ($field instanceof SavableField) {
                $field->save($model, $validation["values"][$fieldName]);
            } else {
                $model->$fieldName = $validation["values"][$fieldName];
            }
        }

        DB::beginTransaction();

        try {
            $isFirstEntry = false;
            if (!$model->exists) {
                $isFirstEntry = true;
                $model->backend_user_id = $loggedUser->id;
            }
            if ($model->exists || !$hasPivot) {
                $model->save();
                $model->touch();
            } else {
                $parentContentType = ContentTypes::find($parentData["contentType"]);
                $parentModelType = $parentContentType->getModelType();
                $parentModel = $parentModelType::find($parentId);
                $prop = $parentData["field"];
                $parentModel->$prop()->save($model);
            }

            $languageFields = $contentType->getFields()->getMultiLanguageFields();
            $languageModels = $model->languages;

            foreach ($languageFields as $field) {
                if ($field->isRelationField() || $field instanceof ExternalField) {
                    continue;
                }

                $fieldName = $field->getName();
                $values = $validation["values"][$fieldName];
                $languageModelType = $model->languages()->getRelated();

                foreach ($values as $languageId => $value) {
                    $languageModel = $languageModels->findByLocale($languageId);
                    if (empty($languageModel)) {
                        $languageModel = new $languageModelType;
                        $languageModel->language_id = $languageId;
                        $languageModels->add($languageModel);
                    }

                    if ($field instanceof SavableField) {
                        $field->save($languageModel, $value);
                    } else {
                        $languageModel->$fieldName = $value;
                    }

                }
            }

            $model->languages()->saveMany($languageModels->all());
            $websiteObjects = $model->websites;

            $websiteObject = $websiteObjects->findByWebsite(Localization::getWebsite()->id);

            if (empty($websiteObject)) {
                $websiteObject = new WebsiteObject;
                $websiteObject->website_id = Localization::getWebsite()->id;
                $websiteObject->content_type = $contentType->getType();

                if ($contentType->isOrderable()) {
                    $position = WebsiteObject::maxPosition(
                        Localization::getWebsite()->id,
                        get_class($model));
                    if (empty($position)) {
                        $position = 0;
                    }
                    $websiteObject->position = $position + 1;
                }

                $websiteObjects->add($websiteObject);
                foreach ($languageModels as $lang) {
                    $woLang = new WebsiteObjectLanguage();
                    $woLang->wo_language_id = $lang->language_id;
                    $woLang->wo_website_id = $websiteObject->website_id;

                    $websiteObject->languages->add($woLang);
                }
            }
            $defaultLang = Localization::getDefaultLocale();
            foreach ($languageModels as $lang) {
                $woLang = $websiteObject->languages->findByLocale($lang->language_id);
                if (isset($validation["values"]["lang_slug"][$lang->language_id])) {
                    $woLang->lang_slug = $validation["values"]["lang_slug"][$lang->language_id];
                } else {
                    $woLang->lang_slug = $validation["values"]["lang_slug"][$defaultLang];
                }
                $woLang->lang_status = $validation["values"]["lang_status"][$lang->language_id];
                $woLang->lang_publish_on = $validation["values"]["lang_publish_on"][$lang->language_id] ?: null;

                if ($defaultLang == $lang->language_id) {
                    $websiteObject->slug = $validation["values"]["lang_slug"][$lang->language_id];
                }
            }

            if (!empty($validation["values"]["sub_type"])) {
                $websiteObject->sub_type = $validation["values"]["sub_type"];
            }
            $websiteObject->status = $validation["values"]["status"];
            $websiteObject->publish_on = $validation["values"]["publish_on"] ?: null;
            $websiteObject->template = $validation["values"]["template"];

            if ($contentType->hasTemplate() ||
                $contentType->getBaseUri($websiteObject->website_id) != false) {
                UriHelper::updateUri($websiteObject, $model, $contentType, false);
            }

            if (!empty($validation["values"]["website_available"]) ||
                $contentType->getShareable() == ContentType::SHAREABLE_GLOBAL) {
                $websiteObject->is_shared = true;

                $websites = Website::select("id")
                    ->where("id", "!=", Localization::getWebsite()->id)->get();
                foreach ($websites as $website) {
                    $websiteObject = $websiteObjects->findByWebsite($website->id);

                    if (empty($websiteObject)) {
                        $websiteObject = new WebsiteObject;
                        $websiteObject->website_id = $website->id;
                        $websiteObject->content_type = $contentType->getType();

                        foreach ($languageModels as $lang) {
                            $woLang = new WebsiteObjectLanguage();
                            $woLang->website_object_id = $websiteObject->id;
                            $woLang->wo_language_id = $lang->language_id;
                            $woLang->wo_website_id = $websiteObject->website_id;

                            $woLang->lang_slug = UriHelper::generateSlug($validation["values"]["lang_slug"][$lang->language_id],
                                $website, $lang->id);

                            $websiteObject->languages->add($woLang);

                            if ($defaultLang == $lang->language_id) {
                                $websiteObject->slug = $validation["values"]["lang_slug"][$lang->language_id];
                            }
                        }

                        $websiteObject->is_shared = true;
                        if ($contentType->getShareable() == ContentType::SHAREABLE_GLOBAL) {
                            $websiteObject->status = "published";
                        } else {
                            $websiteObject->status = "draft";
                        }

                        if ($contentType->hasTemplate() ||
                            $contentType->getBaseUri($websiteObject->website_id) != false) {
                            UriHelper::updateUri($websiteObject, $model, $contentType, false);
                        }

                        if ($contentType->isOrderable()) {
                            $position = WebsiteObject::maxPosition(
                                $website->id,
                                get_class($model));
                            if (empty($position)) {
                                $position = 0;
                            }
                            $websiteObject->position = $position + 1;
                        }

                        $websiteObjects->add($websiteObject);
                    }
                }
            }

            $model->websites()->saveMany($websiteObjects->all());

            foreach ($websiteObjects as $websiteObject) {
                $websiteObject->languages()->saveMany($websiteObject->languages->all());
            }

            foreach ($websiteObjects as $websiteObject) {
                ProcessSearch::dispatch($contentType, $model, true, $websiteObject->website_id);
            }

            //Versioning
            $version = $contentType->getVersion($model);
            $version['backend_user_id'] = $loggedUser->id;
            $revision = ContentVersion::where('object_id', $model->id)
                ->where('object_type', $modelType)
                ->count();
            $version['revision'] = $revision;
            $contentVersion = new ContentVersion($version);
            $contentVersion->save();

            $relationFields = $contentType->getFields()->getRelationFields();

            foreach ($relationFields as $field) {
                $fieldName = $field->getName();
                if (isset($validation["values"][$fieldName])) {
                    $field->save($model, $validation["values"][$fieldName]);
                }
            }

            DB::commit();

            ContentTypeSaved::dispatch($model);
        } catch (Exception $e) {
            DB::rollback();
            Log::error($e);
            throw($e);
        }

        $redirectUrl = request()->path();
        if ($id === false) {
            $redirectUrl .= "/".$model->id;
        }
        session()->forget("_old_input");
        if (request()->ajax()) {
            return response()->json(array(
                "id" => $model->id,
                "title" => $model->title,
                "website_object_id" => $model->website_object_id
            ));
        } else {
            //If has template and has template configuration, jumps to it

            if ($contentType->hasTemplate()) {
                $objectTemplate = $contentType->getTemplates(Localization::getWebsite()->id)[$websiteObject->template];
                if (isset($objectTemplate['contentType'])) {
                    $contentType = ContentTypes::find($objectTemplate['contentType']);
                    $parentData = $contentType->getParent();
                    if (empty($parentData)) {
                        abort(404, trans("http_status.404"));
                    }
                    $modelType = $contentType->getModelType();
                    $configModel = $modelType::where($parentData["field"], $model->id)->first();

                    if (!$configModel) {
                        $redirectUrl = 'admin/content/form-template/'.$objectTemplate['contentType'].'/'.$model->id;
                        return redirect()->to($redirectUrl);
                    }
                }
            }
            return redirect()->to($redirectUrl)->withMessage(trans("backend.save_success"));
        }
    }

    public function deleteIndex()
    {
        $type = request()->get("type");
        $id = request()->get("id");

        if (empty($type) || empty($id) || !is_numeric($id)) {
            return response()->json(array(
                    "error" => "bad_syntax",
                    "description" => trans("http_status.400")
                ),
            400);
        }

        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404, trans("http_status.404"));
        }

        if (!$contentType->userHasPermission("create")) {
            abort(403, trans("http_status.403"));
        }

        $modelType = $contentType->getModelType();

        if (!$this->_deleteContent($modelType, $id)) {
            return response()->json(array(
                    "error" => "not_found",
                    "description" => trans("http_status.404")
                ),
            404);
        }

        return response()->json(array("success" => true));
    }

    protected function _deleteContent($modelType, $id)
    {
        $cache = App::make(Cache::class);
        $model = $modelType::find($id);

        if (empty($model)) {
            return false;
        }

        $currentWebsite = Localization::getWebsite();

        if (!$model->hasWebsite($currentWebsite->id)) {
            return false;
        }

        DB::beginTransaction();
        try {
            $model->delete();
            $wo = WebsiteObject::where("object_id", $id)
                ->where("object_type", $modelType)
                ->where("website_id", Localization::getWebsite()->id)
                ->first();

            // Delete childs
            $childWos = WebsiteObject::where("parent_id", $wo->website_object_id)
                ->where("object_type", $modelType)
                ->where("website_id", Localization::getWebsite()->id)
                ->get();
            foreach ($childWos as $childWo) {
                if (!$this->_deleteContent($modelType, $childWo->object_id)) {
                    DB::rollback();
                    return false;
                }
            }
            $trashCode = random_string('alnum', 5);
            foreach ($wo->languages as $wol) {
                $wol->lang_slug = '<:' . $trashCode . '>' . $wol->lang_slug;
                $wol->save();

                $cache->forget('/' . $wol->wo_language_id . $wol->lang_uri);
            }

            $wo->slug = '<:' . $trashCode . '>' . $wo->slug;
            $wo->parent_id = null;
            $cache->forget($wo->uri == '/' ? 'pc__index__pc' : $wo->uri);
            $wo->save();
            $wo->delete();
            $this->_cleanWebsiteObjectSearches();
            ContentTypeDeleted::dispatch($model);
            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            Log::error($e);
            abort(500);
        }
        return true;
    }

    protected function _cleanWebsiteObjectSearches()
    {
        DB::table("website_object_search")
            ->whereNotExists(function ($query) {
                $query->select(DB::raw(1))
                    ->from("website_objects")
                    ->whereRaw("website_object_search.website_object_id = website_objects.website_object_id")
                    ->whereNull("deleted_at");
            })->delete();
    }

    public function getOrder($type)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404, trans("http_status.404"));
        }

        if (!$contentType->userHasPermission("create")) {
            abort(403, trans("http_status.403"));
        }



        if ($contentType->isHierarchic()) {
            $entries = $contentType->toStructuredList();
        } else {
            $entries = $contentType->toList(null, null, array('position' => 'asc'))->all();
        }

        return view('admin/generic/pages/order', array(
            "contentType" => $contentType,
            "entries" => $entries
        ));
    }

    public function postOrder($type)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404, trans("http_status.404"));
        }

        $website = Localization::getWebsite();
        if (!$contentType->userHasPermission("create")) {
            abort(403, trans("http_status.403"));
        }

        $modelType = $contentType->getModelType();

        $newOrder = request()->input('content_order');
        $newOrder = json_decode($newOrder);

        if (!$newOrder || !is_array($newOrder)) {
            abort(400);
        }

        DB::beginTransaction();
        try {
            $counter = 0;
            $this->_saveOrder($newOrder, $contentType->getModelType(), $website->id, $counter);
            DB::commit();
        } catch (Exception $e) {
            DB::rollback();
            Log::error($e);
            abort(500);
        }

        $redirectUrl = 'admin/content/index/'.$type;
        if (request()->ajax()) {
            return response()->json(array("message" => "OK"));
        } else {
            return response()->redirectTo($redirectUrl)->withMessage(trans("backend.save_success"));
        }
    }

    private function _saveOrder($orderTree, $objectType, $websiteId, &$i, $parent = null)
    {
        foreach ($orderTree as $orderItem) {
            $i++;
            if (!is_numeric($orderItem->id)) {
                abort(400);
            }
            $websiteObject = WebsiteObject::find($orderItem->id);
            if (empty($websiteObject) || $websiteObject->object_type !== $objectType
                || $websiteObject->website_id !== $websiteId) {
                abort(400);
            }
            $websiteObject->position = $i;
            if ($parent) {
                $websiteObject->parent_id = $parent->id;
                if ($websiteObject->object_type == 'Entry') {
                    $websiteObject->uri = $websiteObject->parent->uri.'/'.$websiteObject->slug;
                }
            } else {
                if ($websiteObject->object_type == 'Entry') {
                    $websiteObject->uri = '/'.($websiteObject->slug == 'home' ? '' : $websiteObject->slug);
                }
                $websiteObject->parent_id = null;
            }
            $websiteObject->save();

            if (isset($orderItem->children)) {
                $this->_saveOrder($orderItem->children, $objectType, $websiteId, $i, $orderItem);
            }
        }
    }

    function postDuplicate($type, $id)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        if (!$contentType->userHasPermission("create")) {
            abort(403, trans("http_status.403"));
        }

        $modelType = $contentType->getModelType();

        if (!is_numeric($id)) {
            abort(404);
        }

        $sourceModel = $modelType::find($id);

        if (empty($sourceModel)) {
            abort(404);
        }
        \DB::beginTransaction();
        try {
            $model = ContentType::duplicateContent($contentType, $sourceModel);
            $sourceWebsiteObject = $sourceModel->websites->findByWebsite(Localization::getWebsite()->id);

            if ($contentType->hasTemplate()) {
                $objectTemplate = $contentType->getTemplates(Localization::getWebsite()->id)[$sourceWebsiteObject->template];
                if (isset($objectTemplate['contentType'])) {
                    $templateContentType = ContentTypes::find($objectTemplate['contentType']);
                    $parentData = $templateContentType->getParent();
                    if (empty($parentData)) {
                        abort(404, trans("http_status.404"));
                    }
                    $templateModelType = $templateContentType->getModelType();
                    $configModel = $templateModelType::where($parentData["field"], $sourceModel->id)->first();

                    if ($configModel) {
                        $parentFieldName = $parentData["field"];
                        $duplicateConfigModel = ContentType::duplicateContent(
                            $templateContentType,
                            $configModel,
                            'published',
                            [
                                $parentFieldName => $model->id,
                            ],
                            [
                                'title' => 'template configuration duplication'
                            ]
                        );
                        $duplicateConfigModel->save();
                    }
                }
            }
            \DB::commit();
            return response()->json(array("message" => "OK", "id" => $model->id));
        } catch (Throwable $e) {
            \DB::rollback();
            throw $e;
        }
    }

    public function getBrowser($browser)
    {
        return view('admin.generic.components.browsers.' . $browser);
    }

    public function postExportPages(AdminExportContentListRequest $request)
    {
        $inputData = $request->validated();
        $website = Localization::getWebsite();

        Localization::setActiveLocale($inputData['language']);

        $contentTypes = ContentTypes::allPageable();
        $data = [];
        foreach ($contentTypes as $contentType) {
            if ($inputData['content_type'] && $inputData['content_type'] != $contentType->getType()) {
                continue;
            }

            if ($contentType->hasWebsite($website->id)) {
                $modelName = $contentType->getModelType();
                $tableName = app($modelName)->getTable();

                $query = $modelName::full()->select([
                    $tableName . '.updated_at',
                    $tableName . '.created_at',
                    'content_type',
                    'id',
                    'lang_slug',
                    'title',
                    'template',
                    'status',
                    'lang_status'
                ]);

                if ($inputData['content_type'] == 'project') {
                    $query->addSelect(['is_hero', 'spg_id']);
                }

                $objects = $query->get();
                foreach ($objects as $object) {
                    $lineData = [
                        'type' => $object->content_type,
                        'id' => $object->id,
                        'status' => $object->status,
                        'lang_status' => $object->lang_status,
                        'title' => $object->title,
                        'created_at' => $object->created_at,
                        'updated_at' => $object->updated_at,
                        'slug' => $object->lang_slug,
                        'link' => lang_url($object->lang_uri),
                        'bo_link' => url("admin/content/form/$object->content_type/$object->id")
                    ];
                    if ($inputData['content_type'] == 'project') {
                        $lineData['is_hero'] = ($object->is_hero ? 'Y' : 'N');
                        $lineData['spg_id'] = $object->spg_id;
                    }
                    $data[] = $lineData;
                }
            }

        }

        /* Build csv */
        $columnHeaders = [
            'Type',
            'Object ID',
            'Status',
            'Lang Status',
            'Title',
            'Created Date',
            'Updated Date',
            'Slug',
            'Frontend Link',
            'Back office link'
        ];
        if ($inputData['content_type'] == 'project') {
            $columnHeaders[] = 'Is Hero?';
            $columnHeaders[] = 'P. Code';
        }
        $out = implode(',', $columnHeaders) ."\n";
        foreach ($data as $content) {
            $out .= $content['type'] . ',' . $content['id'] . ',"' . $content['status'] . '","' . $content['lang_status'] . '","' .
                str_replace('"', '""', $content['title']) . '","' . $content['created_at'] . '","' . $content['updated_at'] . '","' . str_replace('"', '""', $content['slug']) . '","' .
                $content['link'] . '","' . $content['bo_link'] . '"';

            if ($inputData['content_type'] == 'project') {
                $out .= ',"' . $content['is_hero'] . '","' . $content['spg_id'] . '"';
            }

            $out .= "\n";
        }

        $filename = 'SP_content_list_' . $inputData['language'] . '_' . Carbon::now() . '.csv';
        return response()->csvattachment($out, $filename);
    }

    public function postShareLink($websiteObjectId, AdminShareLinkRequest $request)
    {
        $inputData = $request->input();
        $wo = WebsiteObject::find($websiteObjectId);

        if (!$wo) {
            return response()->json([
                'success' => false,
                'error' => 'Website object not found'
            ]);
        }

        $wol = $wo->languages->findByLocale($inputData['language']);

        if (!$wol) {
            return response()->json([
                'success' => false,
                'error' => 'Website object language not found'
            ]);
        }

        $shareLink = new ShareLink();
        $shareLink->token = random_string('alnum', 32);
        $shareLink->expires_at = now()->addDays(!empty($inputData['expires']) ? $inputData['expires'] : 3);
        $shareLink->data = [
            'language' => $inputData['language'],
            'websiteObjectId' => $wo->id,
            'lang_uri' => $wol->lang_uri
        ];

        $shareLink->save();

        return response()->json([
            'success' => true,
            'link' => lang_url("/_preview/$shareLink->token", $inputData['language'])
        ]);
    }

    function getTypeInfo($type, $id)
    {
        $contentType = ContentTypes::find($type);

        if (!$contentType->hasWebsite(Localization::getWebsite()->id)) {
            abort(404);
        }

        if (!$contentType->userHasPermission("view")) {
            abort(403, trans("http_status.403"));
        }

        $modelType = $contentType->getModelType();

        if (!is_numeric($id)) {
            abort(404);
        }

        $sourceModel = $modelType::find($id);

        if (empty($sourceModel)) {
            abort(404);
        }

        $infoClass = 'App\Libs\Backoffice\Generic\ContentInfo\\' . $modelType;

        if (!class_exists($infoClass)) {
            abort(404);
        }

        return (new $infoClass)->getInfoView($contentType, $sourceModel);
    }

    public function postExportBlocks()
    {
        $website = Localization::getWebsite();

        $query = Block::full()->select([
            'blocks.updated_at',
            'blocks.created_at',
            'title',
            'id',
            'block_title',
            'type',
            'margin_type_top',
            'margin_type_bottom',
            'status'
        ]);

        $objects = $query->get();

        /* Build csv */

        $out = "Type,Block ID,Status,Block Name,Title,Created Date,Updated Date,Back office link\n";
        foreach ($objects as $block) {
            $out .= $block['type'] . ',' . $block['id'] . ',"' . $block['status'] . '","' .
                str_replace('"', '""', $block['title']) . '","' . str_replace('"', '""', $block['block_title']) . '","' .
                $block['created_at'] . '","' . $block['updated_at'] . '","' . url("admin/content/form/block/$block->id") . '"' . "\n";
        }

        $filename = 'SP_block_list_' . Carbon::now() . '.csv';
        return response()->csvattachment($out, $filename);
    }
}
