<?php

namespace App\Http\Controllers\Admin;

use App\Facades\ContentTypes;
use App\Facades\RequestContext;
use App\Facades\Services\BackendUserService;
use App\Facades\Services\BackofficeService;
use App\Http\Controllers\Controller;
use App\Http\Requests\AdminContentAutoComplete;
use App\Libs\Backoffice\Generic\ContentType;
use App\Models\GenericBackoffice\WebsiteObjectLanguage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ViewErrorBag;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Support\Arr;
use App\Models\MediaItem;
use Throwable;

class ContentController extends Controller
{
    public function getIndex($type)
    {
        $contentType = ContentTypes::find($type);
        return view('admin.generic.pages.list', array("contentType" => $contentType));
    }

    public function postList($type)
    {
        /**@var ContentType $contentType */
        $contentType = ContentTypes::find($type);

        //TODO implement form request
        $page = request()->input("current");
        $sort = request()->input("sort");
        $search = request()->input("searchPhrase");
        $rowCount = request()->input("rowCount");

        if (empty($sort) && $contentType->isOrderable() && !$contentType->isHierarchic()) {
            $sort = array("position" => "asc");
        }
        $list = $contentType->toList($page, $rowCount, $sort, $search);

        return response()->json($list);
    }

    public function getForm($type, $id = false, $parentId = false, $parentContentType = false, $parentFieldName = false, $isPreview = FALSE)
    {
        session()->forget("_old_input");

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

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

        $parentData = $contentType->getParent();

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

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

        $modelType = $contentType->getModelType();

        if (!empty($id)) {
            $model = $modelType::find($id);

            if (is_null($model)) {
                abort(404, trans("response.not_found"));
            }
        } else {
            if (!$contentType->userHasPermission()) {
                abort(403, trans("response.forbidden"));
            }

            $modelType = $contentType->getModelType();
            $model = new $modelType;
        }
        if (
            !$model->exists && (!empty($parentId) && empty($parentData)) ||
            (empty($parentId) && !empty($parentData))
        ) {
            abort(400, trans("response.bad_syntax"));
        }
        RequestContext::set('generic_form_timestamp', time());
        if (request()->ajax()) {
            return view(
                'admin.generic.components.form',
                array(
                    "model" => $model,
                    "contentType" => $contentType,
                    "parentId" => $parentId,
                    "isPreview" => $isPreview,
                )
            );
        } else {
            return view(
                'admin.generic.pages.form',
                array(
                    "model" => $model,
                    "contentType" => $contentType,
                    "parentId" => $parentId,
                    "isPreview" => $isPreview,
                )
            );
        }
    }

    public function getPreview($type, $id = FALSE, $parentId = FALSE, $parentContentType = FALSE, $parentFieldName = FALSE, $isPreview = TRUE)
    {
        return $this->getForm($type, $id, $parentId, $parentContentType, $parentFieldName, $isPreview);
    }

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

        if (empty($originSlug) || empty($langId)) {
            return response()->json(array(
                "error" => "bad_syntax",
                "description" => "The request is missing the slug"
            ), 400);
        }
        $slug = BackofficeService::generateSlug($originSlug, $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 postForm(
        $type,
        $id = false,
        $parentId = false,
        $parentContentType = false,
        $parentFieldName = false
    ) {
        $redirectTo = request()->input('redirect_to') !== '' ? request()->input('redirect_to') : null;
        $contentType = ContentTypes::find($type);

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

        $loggedUser = BackendUserService::getLoggedUser();
        if (!empty($id)) {
            $modelType = $contentType->getModelType();
            $model = $modelType::find($id);

            if (is_null($model)) {
                abort(404, trans("response.not_found"));
            }
        } else {
            $modelType = $contentType->getModelType();
            $model = new $modelType;
            $filters = $contentType->getFilters();
            foreach ($filters as $filter) {
                $model->$filter["field"] = $filter["value"];
            }
        }

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

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

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

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

        //TODO use Form Request?
        $validation = $contentType->getValidation(!$model->exists);

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

        );

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

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

        $validationFails = $validator->fails();
        $errors = $validator->errors();

        $mediaPickerErrors = [];

        // Eeters here if every rule passes
        if (!$validationFails) {
            // get Content type fields
            $contentTypeFields = $contentType->getFields();
            $mediaPickerFields = $contentTypeFields->filter(function ($value) {
                // get all mediaPicker fields in this ContentType
                return $value->getType() === 'mediaPicker' && $value->getAllowed();
            });
            foreach ($mediaPickerFields as $field) {
                // get the allowed extensions from the mediaPicker field
                $allowedExtensions = explode(',', $field->getAllowed());
                // get the ids of the media items
                $ids = json_decode(request()->input($field->getName()));
                // get the Media Item models
                $mediaItems = MediaItem::WhereIn('id', $ids)->get();
                foreach ($mediaItems as $mediaItem) {
                    // if the current media item extension is not in the allowed extensions
                    if (!in_array($mediaItem->extension, $allowedExtensions)) {
                        // manually add the error to the validator MessageBag
                        $errors->add($field->getName(), 'This extension is not allowed');
                        // set validationFails to true so it displays the messageBag errors
                        $validationFails = true;
                    }
                }
            }
        }

        if ($validationFails) {
            $errors = $validator->errors();
            RequestContext::set("errors",  $errors);
            view()->share("errors", (new ViewErrorBag())->put('default', $errors));
            request()->flash();
            if (request()->ajax()) {
                return view(
                    'admin/generic/components/form',
                    array(
                        "model" => $model,
                        "contentType" => $contentType,
                        "parentId" => $parentId,
                        "isPreview" => false,
                    )
                );
            } else {
                return view(
                    'admin/generic/pages/form',
                    array(
                        "model" => $model,
                        "contentType" => $contentType,
                        "parentId" => $parentId
                    )
                );
            }
        }

        $redirectUrl = request()->path();
        if ($id === false) {
            $redirectUrl .= "/" . $model->id;
        }

        try {
            BackofficeService::saveContentType(
                $contentType,
                $model,
                $validation["values"],
                $loggedUser,
                $parentData,
                $parentId,
                $hasPivot
            );
        } catch (Throwable $t) {
            return redirect()->to($redirectUrl)->withMessage($t->getMessage());
        }

        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()) {
                $model->load('websites');
                $websiteObject = $model->websites->first();
                $objectTemplate = $contentType->getTemplates()[$websiteObject->template];
                if (isset($objectTemplate['contentType'])) {
                    $contentType = ContentTypes::find($objectTemplate['contentType']);
                    $parentData = $contentType->getParent();
                    if (empty($parentData)) {
                        abort(404, trans("response.not_found"));
                    }
                    $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);
                    }
                }
            }
            if ($redirectTo) {
                return redirect()->to($redirectTo)->withMessage(trans("backend.save_success"));
            } else {
                return redirect()->to($redirectUrl)->withMessage(trans("backend.save_success"));
            }
        }
    }

    public function postAutoComplete(AdminContentAutoComplete $request, $baseContentype, $field)
    {
        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'];
        //}

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

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

        $mergedResults = [];
        foreach ($objectTypes as $objectType) {
            $contentType = config('backoffice.generic.' . $objectType);
            $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 if ($objectType === 'blocks') {
                $fk = $langTable . '.block_id';
            } else if ($objectType === 'sliderItems') {
                $fk = $langTable . '.slider_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")
                ->where("content_type", $contentType['type']);

            $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());
        }

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

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

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

        try {
            BackofficeService::deleteContentType($contentType, $id);
        } catch (NotFoundHttpException $e) {
            return response()->json(["success" => true]);
        }

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

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

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

        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->userHasPermission()) {
            abort(403, trans("response.forbidden"));
        }

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

        if (!$newOrder || !is_array($newOrder)) {
            abort(400, trans("response.bad_syntax"));
        }

        try {
            BackofficeService::reorderContentType($contentType, $newOrder);
        } catch (BadRequestHttpException $e) {
            abort(400, trans("response.bad_syntax"));
        }

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

    public function getFormTemplate($type, $parentId)
    {

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

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

        $parentData = $contentType->getParent();

        if (empty($parentData)) {
            abort(404, trans("response.not_found"));
        }
        $modelType = $contentType->getModelType();
        $model = $modelType::where($parentData["field"], $parentId)->first();

        if (empty($model)) {
            $loggedUser = BackendUserService::getLoggedUser();
            $model = BackofficeService::createContentTypeTemplate($contentType, $parentId, $loggedUser);
        }
        $url = "/admin/content/form/{$type}/{$model->id}/{$parentId}";


        return response()->redirectTo($url);
    }
}
