<?php namespace Eae\Backoffice\Generic\Fields;

use Eae\Support\Contracts\ListableFieldInterface;
use Eae\Support\Contracts\SearchableFieldInterface;
use Illuminate\Database\Eloquent\Builder;
use Eae\Exception\InvalidConfigurationException;
use LaravelLocalization;
use View;
use Input;
use ContentTypes;
use Config;

class SelectBoxField extends BaseField implements ListableFieldInterface{
    protected $contentType;
    protected $model;
    protected $list;
    protected $defaultValue;
    protected $allowInsert = false;
    protected $boxSearch = false;
    protected $labelField = null;
    protected $mandatory = false;

    public function __construct($config){
        unset($config["multiLanguage"]);
        parent::__construct($config);

        if(empty($config["contentType"]) && empty($config["list"])){
            throw new InvalidConfigurationException("The field {$this->getName()} is missing a content type or a list");
        }

        if(!empty($config["contentType"]) && !empty($config["list"])){
            throw new InvalidConfigurationException("The field {$this->getName()} is can only have a content type or a list");
        }

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


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

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

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

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

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

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

    public function setContentType($contentType){
        $this->contentType = $contentType;
    }

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

    public function setList($list){
        $this->list = $list;
    }

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

    public function setAllowInsert($allowInsert){
        $this->allowInsert = $allowInsert;
    }

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

    public function setBoxSearchable($boxSearch){
        $this->boxSearch = $boxSearch;
    }

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

    public function setMandatory($mandatory = false){
        $this->mandatory = $mandatory;
    }


    public function buildSelect(Builder $query){

        if(!empty($this->contentType)){
            return $this->_buildModelSelect($query);
        }else{
            return $this->_buildListSelect($query);
        }
    }

    private function _buildModelSelect(Builder $query){
        $tablePrefix = $query->getModel()->getTable();
        $model = $this->_getModel();
        $modelTable = $model->getTable();
        $query->leftJoin($modelTable, "{$tablePrefix}.{$this->getName()}", "=", "{$modelTable}.id");

        $languageRelationship = $model->languages();
        $languageModel = $languageRelationship->getRelated();
        $languageFK = $languageRelationship->getForeignKey();
        $query->leftJoin($languageModel->getTable(),
            function($join) use($model, $languageFK, $languageModel) {
                $join->on($model->getQualifiedKeyName(), "=", $languageFK)
                    ->where("{$languageModel->getTable()}.language_id", "=", LaravelLocalization::getCurrentLocale());
            });

        $query->addSelect("{$languageModel->getTable()}.title as relation." . $this->getName());
        return $query;
    }

    private function _buildListSelect(Builder $query){
        if($this->isMultiLanguage()){
            $tablePrefix = $query->getModel()->languages()->getRelated()->getTable();
        }else{
            $tablePrefix = $query->getModel()->getTable();
        }

        $query->addSelect("{$tablePrefix}.{$this->name}");
        return $query;
    }

    public function buildWhere(Builder $query, $searchPhrase){
        if(empty($searchPhrase) || !$this->isSearchable()){
            return $query;
        }

        if(!empty($this->contentType)){
            return $this->_buildModelWhere($query, $searchPhrase);
        }else{
            return $this->_buildListWhere($query, $searchPhrase);
        }
    }

    private function _buildModelWhere(Builder $query, $searchPhrase){
        $tablePrefix = $this->_getModel()->languages()->getRelated()->getTable();

        $query->orWhere("{$tablePrefix}.title", 'like', "%{$searchPhrase}%");
        return $query;
    }

    private function _buildListWhere(Builder $query, $searchPhrase){
        $list = array_where($this->list, function($key, $value) use ($searchPhrase){
            return str_contains(strtolower($value), strtolower($searchPhrase));
        });
        $tablePrefix = $query->getModel()->getTable();

        if(!empty($list)){
            $query->orWhereIn("{$tablePrefix}.{$this->getName()}", array_keys($list));
        }
        return $query;
    }

    public function buildOrder(Builder $query, $sortOrder = "asc"){
        if(!empty($this->contentType)){
            return $this->_buildModelOrder($query, $sortOrder);
        }else{
            return $this->_buildListOrder($query, $sortOrder);
        }
    }

    private function _buildModelOrder(Builder $query, $sortOrder = "asc"){
        $tablePrefix = $this->_getModel()->languages()->getRelated()->getTable();
        $query->orderBy("{$tablePrefix}.title", $sortOrder);
        return $query;
    }

    private function _buildListOrder(Builder $query, $sortOrder = "asc"){
        $list = $this->list;
        $sortFunction = "_reorderAscList";
        if(strtolower($sortOrder) != 'asc'){
            $sortFunction = "_reorderDescList";
        }
        $tablePrefix = $query->getModel()->getTable();

        uasort($list, array($this, $sortFunction));
        $sortValues = implode(" ','" ,array_keys($list));
        $query->orderByRaw("field({$tablePrefix}.{$this->getName()}, '{$sortValues}')");

        return $query;
    }

    protected function _reorderAscList($listItem1, $listItem2){
        $firstItem = strtolower($listItem1);
        $secondItem = strtolower($listItem2);

        if ($firstItem == $secondItem) {
            return 0;
        }

        return ($firstItem > $secondItem) ? 1 : -1;
    }

    protected function _reorderDescList($listItem1, $listItem2){
        $firstItem = strtolower($listItem1);
        $secondItem = strtolower($listItem2);

        if ($firstItem == $secondItem) {
            return 0;
        }

        return ($firstItem < $secondItem) ? 1 : -1;
    }

    public function toGridHeader(){
        $header = '<th data-column-id="relation.' . $this->getName() . '"';

        if(!empty($this->list)){
            $header .= ' data-formatter="staticList"';
        }
        $header .= '>' . ucfirst($this->getLabel()) . '</th>';
        return $header;
    }

    private function _getModel(){
        if(empty($this->model)){
            $contentType = ContentTypes::find($this->contentType);
            $modelType = $contentType->getModelType();
            $this->model = new $modelType;

        }

        return $this->model;
    }

    public function getCurrentValue($model){
        $fieldName = $this->getName();
        if(Input::has($fieldName)){
            return Input::get($fieldName);
        }

        if($model->exists){
            return $model->$fieldName;
        }

        if(!empty($this->defaultValue)){
            return $this->defaultValue;
        }

        return null;
    }

    public function toForm($model, $enabled = true, $hidden = false){
        if(!$this->isMandatory()){
            $list = ['' => ''] + $this->_fetchList();
        }else {
            $list = $this->_fetchList();
        }

        $name = $this->getName();
        $value = null;

        if($model->exists){
            $value = $model->$name;
        } elseif ($this->defaultValue) {
            $value = $this->defaultValue;
        }

        $contentType = false;

        if($this->getAllowInsert()){
            $contentType = ContentTypes::find($this->getContentType());
            $contentType = array(
                "type" => $contentType->getType(),
                "label" => ucfirst($contentType->getSingularLabel())
            );
        }

        if($this->isDisabled()){
            $enabled = false;
        }

        return View::make(
            "admin.generic.components.forms.selectbox",
            array(
                "id"        => $this->getName(),
                "name"      => $this->getName(),
                "errorKey"  => $this->getName(),
                "label"     => $this->getLabel(),
                "value"     => $value,
                "list"      => $list,
                "hide"      => $hidden,
                "enabled"   => $enabled,
                "parentHidden"  => ($hidden && !empty($this->parent)),
                "parent"        => $this->getParent(),
                "contentType"   => $contentType,
                "searchable"    => $this->isBoxSearchable(),
                "info"          => $this->getInfo()
            ));
    }

    private function _fetchList(){
        if(!empty($this->list)){
            return $this->list;
        }

        $relationshipModel = $this->_getModel();
        $relationshipTable = $relationshipModel->getTable();

        $languageRelationship = $relationshipModel->languages();
        $languageModel = $languageRelationship->getRelated();
        $languageTable = $languageModel->getTable();

        if ($this->labelField == null) {
            $this->labelField = $languageTable . '.title';
        }
        return $relationshipModel->full()
            ->select("{$relationshipTable}.id", $this->labelField)
            ->orderBy("{$languageTable}.title", "asc")->lists($this->labelField, "id");
    }

    public function getValidationData($copyAllLang = false){
        $validation = parent::getValidationData();
        if($validation["values"][$this->getName()] == ""){
            $validation["values"][$this->getName()] = null;
        }

        return $validation;
    }

    public function toArray(){
        $array = parent::toArray();
        if(!empty($this->list)){
            $array["list"] = $this->list;
        }
        return $array;
    }

    public static function getScript(){
        $locale = LaravelLocalization::getCurrentLocale();

        return array(
            "selectBoxField" => Config::get('path.backoffice.js_path') . '/view/generic/backend-generic-selectbox.js',
            "selectBoxSearchLang" => Config::get('path.backoffice.js_path') . "/select/i18n/defaults-{$locale}.js");

    }
    /**
     * Simple level 2 search indexing. only works for multilang and for title field
     * Not to be used in any outher case!
     *
     * @param mixed $model
     * @param mixed $view
     */
    public function getSearchStructure($model, $view = false){
        $searchData = array();

        $fieldName = $this->getName();

        if (!$this->contentType || !$model->$fieldName) {
            return null;
        }

        $childModel = $this->_getModel();
        $childModel = $childModel::find($model->$fieldName);

        foreach($childModel->languages as $languageModel){
            if(!empty($languageModel->title)){
                if($view){
                    $value = cut_string($languageModel->title,500);
                }else{
                    $value = $languageModel->title;
                }
                $searchData[$languageModel->language_id] = $value;
            }
        }
        return $searchData;
    }
}
  

