<?php

namespace App\Libs\Backoffice\Fields;

use App\Facades\Backoffice\ContentTypes;
use App\Libs\Backoffice\Contracts\SavableField;
use App\Libs\Backoffice\Exceptions\InvalidConfigurationException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use stdClass;

class MultiplePickerField extends BaseField implements SavableField
{
    protected $order = false;
    protected $objectTypes = false;
    protected $maxSize = false;
    protected $minSize = 0;
    protected $websiteObjectRelation = false;
    protected $allowInsert = false;
    protected $listExtraFields = [];

    public function __construct($config)
    {
        unset($config["multiLanguage"]);
        unset($config["inList"]);
        unset($config["search"]);
        unset($config["sort"]);

        parent::__construct($config);

        $this->relationField = true;

        if (empty($config["objectTypes"])) {
            throw new InvalidConfigurationException("The {$this->name} configuration is missing the object types");
        }

        $this->objectTypes = $config["objectTypes"];

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

        if ($this->websiteObjectRelation === false && count($this->objectTypes) > 1) {
            throw new InvalidConfigurationException("The {$this->name} multi picker field cannot have more than one object type if it is not multi website");
        }

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

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

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

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

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

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

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

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

    public function getObjectTypesModelsType()
    {
        $modelsType = array();
        foreach ($this->objectTypes as $objectType) {
            $contentType = ContentTypes::find($objectType);
            $modelsType[] = $contentType->getModelType();

        }
        return $modelsType;
    }

    public function getContentTypes()
    {
        $contentTypes = array();
        foreach ($this->objectTypes as $objectType) {
            $contentType = ContentTypes::find($objectType);
            $contentTypes[] = $contentType;
        }
        return $contentTypes;
    }

    public function setObjectTypes($objectTypes = array())
    {
        $this->objectTypes = $objectTypes;
    }

    public function isMultipleTypes()
    {
        return !empty($this->objectTypes) && count($this->objectTypes) > 1;
    }

    public function setwebsiteObjectRelation($websiteObjectRelation)
    {
        $this->websiteObjectRelation = $websiteObjectRelation;
    }

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

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

    public function setMaxSize($maxSize)
    {
        $this->maxSize = $maxSize;
    }

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

    public function setMinSize($minSize = 0)
    {
        $this->minSize = $minSize;
    }

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

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

    public function getValidation()
    {
        $rules = "array";

        if ($this->minSize > 0) {
            if ($this->conditions) {
                foreach ($this->conditions as $condition) {
                    $value = $condition['value'];
                    if ($condition->operator == 'in') {
                        $value = [$condition['value']];
                    }
                    $rules .= "|required_if:{$condition['field']}," . implode(",", $value);
                    $testValue = request()->input($condition['field']);
                    if (!is_null($testValue) && in_array($testValue, $value)) {
                        $rules .= "|min:".$this->minSize;
                    }
                }
            } else {
                $rules .= "|required|min:".$this->minSize;
            }
        }

        if ($this->maxSize > 0) {
            $rules .= "|max:".$this->maxSize;
        }

        return $rules;
    }

    public function getData(Model $model, $enabled = true, $hidden = false)
    {
        $contentTypes = $this->getContentTypes();
        if ($this->isWebsiteObjectRelation()) {
            $pickedList = new Collection();
            if ($model->exists) {
                $objs = $model->related($this->name);

                foreach($objs as $pickedObj) {
                    $obj = new stdClass();
                    $obj->id = $pickedObj->id;
                    $obj->object_id = $pickedObj->website_object_id;
                    $obj->type = $pickedObj->content_type;
                    $obj->title = $pickedObj->title;
                    $pickedList->push($obj);
                }
            }

            $value = $pickedList->pluck('object_id')->toArray();
        } else {
            $contentType = head($contentTypes);
            $relationshipName = $this->name;
            $relationship = $model->$relationshipName();
            $relationTableName = $relationship->getTable();
            $relationModel = $relationship->getRelated();

            $query = $relationModel->full()
                ->select("id", "title", "website_objects.website_object_id as object_id", DB::raw("'" . $contentType->getType() . "' as type"))
                ->join($relationTableName, $relationModel->getTable().'.'.$relationship->getRelatedKeyName(), "=",
                    $relationship->getQualifiedRelatedPivotKeyName());

            if ($this->isOrderable()) {
                $query->orderBy("{$relationTableName}.position", "asc");
            } else {
                $query->orderBy("title", "asc");
            }

            if ($model->exists) {
                $query->where($relationship->getQualifiedForeignPivotKeyName(), '=', $model->id);
                $pickedList = $query->get();
            } else {
                $pickedList = new Collection();
            }
            $value = $pickedList->pluck('id')->toArray();
        }

        return [
            'name' => $this->getName(),
            'type' => ucfirst($this->getType()),
            'label' => $this->getLabel(),
            'isOrderable' => $this->isOrderable(),
            'maxSize' => $this->getMaxSize(),
            'value' => $value,
            'pickedList' => $pickedList,
            'multipleTypes' => false,
            'hide' => $hidden,
            'enabled' => $enabled,
            'conditions' => $this->conditions,
            'allowInsert' => $this->getAllowInsert(),
            'isWebsiteObjectRelation' => $this->isWebsiteObjectRelation(),
            'info' => $this->getInfo(),
            'listExtraFields' => $this->listExtraFields,
            'contentTypes' => array_map(function ($contentType) {
                    return [
                        'type' => $contentType->getType(),
                        'label' => $contentType->getSingularLabel()
                    ];
                }, $contentTypes)
        ];
    }

    public function getValidationDataRules($model = null, $prefix = '')
    {
        $validation = array(
            "rules" => array(),
            "labels" => array()
        );

        $fieldName = $prefix . $this->getName();
        $rules = $this->getValidation();

        if (!empty($rules)) {
            $validation["rules"][$fieldName] = $this->getValidation();
            $validation["labels"][$fieldName] = $this->getLabel();
        }

        return $validation;
    }

    public function save(Model $model, $values)
    {
        if ($this->isWebsiteObjectRelation()) {
            return $this->_saveWebsite($model, $values);
        } else {
            return $this->_saveNoWebsite($model, $values);
        }
    }

    protected function _saveNoWebsite($model, $values)
    {
        $relationName = $this->getName();

        $ids = Arr::flatten($values);

        if ($this->isOrderable()) {
            $syncData = array();
            $position = 1;
            foreach ($ids as $id) {
                $syncData[$id] = array("position" => $position);
                $position = $position + 1;
            }

            $model->$relationName()->sync($syncData);
        } else {
            $model->$relationName()->sync($ids);
        }
    }

    protected function _saveWebsite($model, $values)
    {
        if (empty($this->objectTypes)) {
            return;
        }

        $type = $this->getName();
        $websiteObject = $model->getActiveWebsiteEntry();
        $relation = $websiteObject->related();

        $ids = Arr::flatten($values);

        if ($this->isOrderable()) {
            $syncData = array();
            $position = 1;
            foreach ($ids as $id) {
                $syncData[$id] = array("position" => $position, "type" => $type);
                $position = $position + 1;
            }

            $relation->wherePivot("type", $type)->sync($syncData);
        } else {
            $syncData = array();
            foreach ($ids as $id) {
                $syncData[$id] = array("type" => $type);
            }
            $relation->wherePivot("type", $type)->sync($syncData);
        }
    }

    public function toArray()
    {
        $array = parent::toArray();
        $array["maxSize"] = $this->maxSize;
        $array["minSize"] = $this->minSize;
        return $array;
    }
}


