<?php

use Eae\Backoffice\Grid as EaeGrid;
use Eae\Backoffice\Generic\ContentType;
use Eae\Support\Contracts\SavableFieldInterface;
use Eae\Support\Contracts\ExternalFieldInterface;
use Eae\Backoffice\Generic\Fields\MediaPickerField;

class AdminContentController extends Controller {

    public function __construct(){
        $this->beforeFilter('csrf', array('on' => array('post', 'delete')));
    }


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

        $user = Auth::backend()->user();
        if(!$user->hasPermission("cms.manage")){
            App::abort(403, Lang::get("http_status.403"));
        }

        return View::make('admin/generic/pages/list', array("contentType" => $contentType));
    }

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

        $user = Auth::backend()->user();

        if(!$user->hasPermission("cms.manage")){
            App::abort(403, Lang::get("http_status.403"));
        }

        $page = Input::get("current");
        $sort = Input::get("sort");
        $search = Input::get("searchPhrase");
        $rowCount = Input::get("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 postCheckSlug(){
        $originSlug = Input::get("slug");
        $langId = Input::get("lang");

        if(empty($originSlug) || empty($langId)){
            return Response::json(array(
                "error" => "bad_syntax",
                "description" => "The request is missing the slug"
            ), 400);
        }
        $slug = $this->_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));
        }
    }

    private function _generateSlug($originSlug, $langId){
        $originSlug = urlize($originSlug);
        $slug = $originSlug;

        $slugCounter = 1;
        while(WebsiteObject::hasSlug($slug, $langId) && $slugCounter <= 100){
            $slug = $originSlug . "-" . $slugCounter;
            $slugCounter++;
        }

        if($slugCounter == 100){
            return false;
        }else{
            return $slug;
        }
    }

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

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

        if(!$contentType->userHasPermission()){
            App::abort(403, Lang::get("http_status.403"));
        }

        $parentData = $contentType->getParent();

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

        if(empty($model)){
            $model = $this->_insertFormTemplate($contentType,$parentId);
        }
        $url = "/admin/content/form/{$type}/{$model->id}/{$parentId}";


        return Redirect::to($url);
    }

    private function _insertFormTemplate($contentType, $parentId){
        $loggedUser = Auth::backend()->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)){
            App::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->first();

            $websiteObject = new WebsiteObject;
            $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_uri = null;

                $woLang->save();
            }

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

        return $model;
    }

    public function getForm($type, $id = false, $parentId = false, $parentContentType = false, $parentFieldName = false){

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

        if(!$contentType->userHasPermission()){
            App::abort(403, Lang::get("http_status.403"));
        }

        $parentData = $contentType->getParent();
        //var_dump($parentData); die;
        if ($parentContentType && $parentFieldName) {
            $parentType = ContentTypes::find($parentContentType);
            $parentField = $parentType->getFields()->find($parentFieldName);
            if (!$parentField || $parentField->getObjectType() != $type) {
                App::abort(404);
            }

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

        $modelType = $contentType->getModelType();

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

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

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

        }else{
            if(!$contentType->userHasPermission()){
                App::abort(403, Lang::get("http_status.403"));
            }
            $modelType = $contentType->getModelType();
            $model = new $modelType;
        }
        if(!$model->exists && (!empty($parentId) && empty($parentData)) ||
            (empty($parentId) && !empty($parentData))){
             App::abort(400, Lang::get("http_status.400"));
        }

        if(Request::ajax()){
            return View::make('admin/generic/components/form',
                array(
                    "model" => $model,
                    "contentType" => $contentType,
                    "parentId" => $parentId));
        }else{
            return View::make('admin/generic/pages/form',
                array(
                    "model" => $model,
                    "contentType" => $contentType,
                    "parentId" => $parentId));
        }


    }

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

        if (!$contentType->userHasPermission()) {
            App::abort(403, Lang::get("http_status.403"));
        }

        if (!$contentType->getBaseUri()) {
            App::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);
            $this->_updateUri($websiteObject, $contentType);
        }

        echo 'Success!';
    }
    private function _updateUri ($websiteObject, $contentType, $save = true) {
        $uri = $contentType->getBaseUri();
        $languages = getAvailableLanguages();
        $defaultLang = getDefaultLanguage();

        $defaultUri = "";
        if ($websiteObject->parent) {
            $parent = $websiteObject->parent;

            foreach ($languages as $langCode => $lang) {
                $parentWoLang = $parent->languages->findByLocale($langCode);
                $woLang = $websiteObject->languages->findByLocale($langCode);
                $woLang->lang_uri = $parentWoLang->lang_uri . '/' . $woLang->lang_slug;
                if ($defaultLang == $langCode) {
                    $defaultUri = $woLang->lang_uri;
                }
                if ($save) {
                    $woLang->save();
                }
            }
        } else {
            if ($websiteObject->slug == 'home') {
                $defaultUri = '/';
                foreach ($languages as $langCode => $lang) {
                    $woLang = $websiteObject->languages->findByLocale($langCode);
                    $woLang->lang_uri = $defaultUri;
                    if ($save) {
                        $woLang->save();
                    }
                }
            } else {
                  foreach ($languages as $langCode => $lang) {
                      $woLang = $websiteObject->languages->findByLocale($langCode);

                      if (is_array($uri)) {
                          $uriLang = $uri[$langCode];
                      } else {
                          $uriLang = $uri;
                      }
                      $woLang->lang_uri = $uriLang . '/' . $woLang->lang_slug;
                      if ($defaultLang == $langCode) {
                          $defaultUri = $woLang->lang_uri;
                      }
                      if ($save) {
                          $woLang->save();
                      }
                  }
            }
        }
        $websiteObject->uri = $defaultUri;
        if ($save) {
            $websiteObject->save();
        }

        if ($websiteObject->website_object_id) {
            $children = $websiteObject->children;
            foreach ($children as $child) {
                $this->_updateUri($child, $contentType, $save);
            }
        }
    }

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

        if(!$contentType->userHasPermission()){
            App::abort(403, Lang::get("http_status.403"));
        }

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

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

            if(empty($model)){
                App::abort(404);
            }
        }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) {
                App::abort(404);
            }

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

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

        $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 = $this->_generateSlug($originSlug, $langCode);
            $validation["values"]["lang_slug"][$langCode] = ($slug ? $slug : '');
        }

        if ($validator->fails()){

            // Removed flash since it doesn't seem to be used anymore and it's causing errors on production env
            // Input::flash();
            RequestContext::set("errors", $validator->getMessageBag());
            View::share("errors", $validator->getMessageBag());

            if(Request::ajax()){
                return View::make('admin/generic/components/form',
                    array(
                        "model" => $model,
                        "contentType" => $contentType,
                        "parentId" => $parentId));
            }else{
                return View::make('admin/generic/pages/form',
                    array(
                        "model" => $model,
                        "contentType" => $contentType,
                        "parentId" => $parentId));
            }
        }

        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 ExternalFieldInterface){
                continue;
            }
            $fieldName = $field->getName();
            if($field instanceof SavableFieldInterface){
                $field->save($model, $validation["values"][$fieldName]);
            }else{
                $model->$fieldName = $validation["values"][$fieldName];
            }
        }

        DB::beginTransaction();

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

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

            foreach($languageFields as $field){
                if($field->isRelationField() || $field instanceof ExternalFieldInterface){
                    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 SavableFieldInterface){
                        $field->save($languageModel, $value);
                    }else{
                        $languageModel->$fieldName = $value;
                    }

                }
            }

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

            $websiteObject = $websiteObjects->first();

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

                if($contentType->isOrderable()){
                    $position = WebsiteObject::maxPosition(
                        class_basename($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;

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

            $defaultLang = getDefaultLanguage();
            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];
                }

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

            if ($contentType->hasTemplate() ||
                $contentType->getBaseUri() != false) {
                $this->_updateUri($websiteObject, $contentType, false);
            }

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

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

            if($contentType->isSearchable()){
                $searchContents = $contentType->getSearchStructure($model);

                foreach($websiteObjects as $websiteObject){
                    $websiteObject->searches()->delete();
                    if ($websiteObject->status == 'draft') {
                        continue;
                    }

                    if(isset($searchContents)){
                        foreach($searchContents as $locale => $searchContent){
                            $search = new WebsiteObjectSearch($searchContent);
                            $search->language_id = $locale;
                            $websiteObject->searches()->save($search);
                        }
                    }
                }
            }else{
                $websiteObject->searches()->delete();
            }

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

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

            DB::commit();
        }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()[$websiteObject->template];
                if (isset($objectTemplate['contentType'])) {
                    $contentType = ContentTypes::find($objectTemplate['contentType']);
                    $parentData = $contentType->getParent();
                    if(empty($parentData)){
                        App::abort(404, Lang::get("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(Lang::get("backend.save_success"));
        }
    }

    public function deleteIndex(){
        $type = Input::get("type");
        $id = Input::get("id");
        $fullDelete = Input::get("fullDelete", false);

        if(empty($type) || empty($id) || !is_numeric($id)){
            return Response::json(array(
                "error" => "bad_syntax",
                "description" => Lang::get("http_status.400")),
                400);
        }

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

        if(!$contentType->userHasPermission()){
            App::abort(403, Lang::get("http_status.403"));
        }

        $modelType = $contentType->getModelType();

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

        if(empty($model)){
            return Response::json(array(
                "error" => "not_found",
                "description" => Lang::get("http_status.404")),
                404);
        }

        DB::beginTransaction();

        try{
            $model->delete();
            WebsiteObject::where("object_id", $id)
                    ->where("object_type", $modelType)
                    ->delete();
            $this->cleanWebsiteObjects();
            $this->_cleanWebsiteObjectSearches();
            DB::commit();
        } catch (Exception $e) {
            DB::rollback();
            Log::error($e);
            App::abort(500);
        }

        return Response::json(array("success" => true));
    }

    /**
    * Cleans the website objects table for objects that got deleted by database
    * foreign key cascade deletes
    *
    */
    protected function cleanWebsiteObjects() {
        $contentTypes = ContentTypes::all();

        foreach ($contentTypes as $contentType) {
            $modelType = $contentType->getModelType();
            $model = new $modelType();
            $table = $model->getTable();

            $toDelete = WebsiteObject::where('content_type', $contentType->getType())
                ->whereNotExists(function($query) use ($table) {
                    $query->select(DB::raw(1))
                        ->from($table)
                        ->whereRaw(WebsiteObject::getTableName() . ".object_id = {$table}.id");
            })->delete();
        }
    }

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

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

        if(!$contentType->userHasPermission()){
            App::abort(403, Lang::get("http_status.403"));
        }

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

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

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


        if(!$contentType->userHasPermission()){
            App::abort(403, Lang::get("http_status.403"));
        }

        $modelType = $contentType->getModelType();

        $newOrder = Input::get('content_order');
        $newOrder = json_decode($newOrder);

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

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

        $redirectUrl = 'admin/content/index/' . $type;
        if(Request::ajax()){
            return Response::json(array("message" => "OK"));
        }else{
            return Redirect::to($redirectUrl)->withMessage(Lang::get("backend.save_success"));
        }

    }

    private function _saveOrder($orderTree, $objectType, &$i, $parent = null) {
        foreach ($orderTree as $orderItem) {
            $i++;
            if (!is_numeric($orderItem->id)) {
                App::abort(400);
            }
            $websiteObject = WebsiteObject::find($orderItem->id);
            if (empty($websiteObject) || $websiteObject->object_type !== $objectType) {
                App::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, $i, $orderItem);
            }
        }
    }

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

        $user = Auth::backend()->user();
        if(!$user->hasPermission("cms.manage")){
            App::abort(403, Lang::get("http_status.403"));
        }

        $searchTerm =  Input::get('searchTerm', '');
        $cleanedSearchTerm  = Formatter::transformItem($searchTerm, "strip_tags|xss_clean|trim");

        if(empty($cleanedSearchTerm)){
            return Response::json(array(
                "error" => Config::get("error.not_found"),
                "description" => Lang::get("response.not_found")
            ),404);
        }


        $results = $contentType->autoComplete($cleanedSearchTerm);

        return Response::json($results,200);

    }
}