<?php

namespace App\Libs\Backoffice\Generic\Fields;

use App\Libs\Contracts\Backoffice\DuplicatableField;
use App\Libs\Contracts\Backoffice\SavableField;
use App\Libs\Contracts\Backoffice\VersionableField;
use App\Libs\Exception\InvalidConfigurationException;
use App\Libs\Facades\ContentTypes;
use App\Libs\Facades\Localization;
use App\Libs\Facades\RequestContext;
use App\Models\WebsiteObject;

class LinkField extends BaseField implements SavableField, VersionableField, DuplicatableField
{
    const OBJECT_TYPES = ["project", "page", "solution", "case_study", "publication", "contact", "pardot_form", "news", "blog_post", "event", "overlay", "sector"];

    protected $required = false;
    protected $objectTypes = array();
    protected $maxLabel = 0;

    public function __construct($config, $contentType = null)
    {
        unset($config["validation"]);
        unset($config["preValidation"]);
        unset($config["inList"]);
        unset($config["search"]);
        unset($config["sort"]);

        parent::__construct($config, $contentType);

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

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

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

    public function isRequired()
    {
        return $this->required;
    }

    public function setRequired($required)
    {
        $this->required = $required;
    }

    public function toForm($model, $enabled = true, $hidden = false)
    {
        $html = "";

        $fieldName = $this->getName();
        $label = "";
        $isExternal = false;
        $isNewtab = false;
        $enabled = true;
        $selectedObjectId = null;
        $selectedObject = null;
        $linkUrl = "";
        $linkLabel = "";


        /*
        $websiteModel = new WebsiteObject();

        $relation = $websiteModel->related();

        $query = WebsiteObject::with("objectable")
            ->whereIn("object_type", $this->getObjectTypesModelsType())
            ->where("website_id", Localization::getWebsite()->id);

        $objects = $query->get();


        $fullList = array();

        foreach ($this->getContentTypes() as $contentType) {
            $fullList[$contentType->getModelType()] = array(
                "label" => ucfirst($contentType->getLabel()),
                "list" => array()
            );
        }


        foreach ($objects as $object) {
            $fullList[$object->object_type]["list"][] = (object) array(
                "id" => $object->id,
                "title" => $object->object_type === 'Contact' ? $object->objectable->name : $object->objectable->title
            );
        }

        foreach ($fullList as $listType) {
            usort($listType["list"], function ($firstItem, $secondItem) {
                if ($firstItem->title == $secondItem->title) {
                    return 0;
                }

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

        }

        */
        $postData = request()->old($this->getName());

        $errors = RequestContext::get("errors");
        $hasErrors = false;

        $html = "";
        if ($this->isMultiLanguage()) {
            $languages = Localization::getSupportedLanguages();
            $defaultLang = Localization::getDefaultLocale();

            foreach ($languages as $language) {
                $hasErrors = false;
                $name = $fieldName."[{$language->id}]";
                $id = $fieldName.random_string('alnum', 4)."_{$language->id}";
                $errorKey = $fieldName.".".$language->id;
                $isExternal = false;
                $isNewtab = false;
                $selectedObjectId = null;
                $selectedObject = null;
                $linkUrl = "";
                $linkLabel = "";

                if (!empty($errors) && !$errors->isEmpty()) {
                    if ($errors->has("{$this->getName()}.{$language->id}.label") ||
                        $errors->has("{$this->getName()}.{$language->id}.url") ||
                        $errors->has("{$this->getName()}.{$language->id}.selectedObjectId")) {
                        $hasErrors = true;
                    }

                    if (empty($postData[$language->id]['isExternal']) && $postData[$language->id]['selectedObjectId']) {
                        $selectedObjectId = $postData[$language->id]['selectedObjectId'];
                        $selWo = WebsiteObject::where('website_object_id', $selectedObjectId)->first();
                        if ($selWo) {
                            $selectedObject = [
                                'title' => $selWo->objectable->title . ' (' . $selWo->content_type . ')',
                                'object_id' => $selectedObjectId,
                            ];
                        }
                    }
                } else {
                    if ($model->exists) {
                        $languageModel = $model->languages->findByLocale($language->id);

                        if (!empty($languageModel)) {
                            $value = $languageModel->$fieldName;
                        }

                        if (!empty($value)) {
                            $value = json_decode($value);
                            $linkLabel = $value->label;
                            $isExternal = $value->isExternal;
                            $isNewtab = !empty($value->isNewtab) ? $value->isNewtab : false;
                            $linkUrl = $isExternal ? $value->url : null;
                            if (!$isExternal && $value->objectId) {
                                $selectedObjectId = $value->objectId;
                                $selWo = WebsiteObject::where('website_object_id', $value->objectId)->first();
                                if ($selWo) {
                                    $selectedObject = [
                                        'title' => $selWo->objectable->title . ' (' . $selWo->content_type . ')',
                                        'object_id' => $value->objectId,
                                    ];
                                }
                            }
                        }
                    } else {
                        $isExternal = isset($postData[$language->id]['isExternal']);
                        $isNewtab = isset($postData[$language->id]['isNewtab']);
                    }
                }

                $html .= view(
                    "admin.generic.components.forms.link",
                    array(
                        "id" => $id,
                        "errorKey" => $errorKey,
                        "hasErrors" => $hasErrors,
                        "name" => $name,
                        "fieldName" => $fieldName,
                        "label" => $this->getLabel(),
                        "language" => $language->id,
                        "languages" => $languages,
                        "defaultLang" => $defaultLang,
                        "enabled" => $enabled,
                        "parentHidden" => ($hidden && !empty($this->parent)),
                        "parent" => $this->parent,
                        "required" => $this->isRequired(),
                        "maxLength" => 50,
                        // "fullList" => $fullList,
                        "hide" => ($hidden || $language->id != $defaultLang),

                        "isExternal" => $isExternal,
                        "isNewtab" => $isNewtab,
                        "linkLabel" => $linkLabel,
                        "selectedObjectId" => $selectedObjectId,
                        "selectedObject" =>  $selectedObject,
                        "linkUrl" => $linkUrl,
                        "info" => $this->getInfo(),
                        "blocksMode" => $this->blocksMode,
                        "searchUrl" => url("admin/content/auto-complete/".$this->contentType->getType()."/".$this->name),
                        "objectTypes" => self::OBJECT_TYPES
                    ));
            }
        } else {
            if (!empty($errors) && !$errors->isEmpty()) {
                if ($errors->has("{$this->getName()}.label") ||
                    $errors->has("{$this->getName()}.url") ||
                    $errors->has("{$this->getName()}.selectedObjectId")) {
                    $hasErrors = true;
                }

                if (empty($postData['isExternal']) && $postData['selectedObjectId']) {
                    $selectedObjectId = $postData['selectedObjectId'];
                    $selWo = WebsiteObject::where('website_object_id', $selectedObjectId)->first();
                    if ($selWo) {
                        $selectedObject = [
                            'title' => $selWo->objectable->title . ' (' . $selWo->content_type . ')',
                            'object_id' => $selectedObjectId,
                        ];
                    }
                }
            } else {
                if ($model->exists) {
                    $value = $model->$fieldName;

                    if (!empty($value)) {
                        $value = json_decode($value);
                        $linkLabel = $value->label;
                        $isExternal = $value->isExternal;
                        $isNewtab = $value->isNewtab;
                        $linkUrl = $isExternal ? $value->url : null;

                        if (!$isExternal && $value->objectId) {
                            $selectedObjectId = $value->objectId;
                            $selWo = WebsiteObject::where('website_object_id', $value->objectId)->first();
                            if ($selWo) {
                                $selectedObject = [
                                    'title' => $selWo->objectable->title . ' (' . $selWo->content_type . ')',
                                    'object_id' => $value->objectId,
                                ];
                            }
                        }
                    }
                }
            }

            $html .= view(
                "admin.generic.components.forms.link",
                array(
                    "id" => $this->getName(),
                    "errorKey" => $this->getName(),
                    "hasErrors" => $hasErrors,
                    "name" => $this->getName(),
                    "fieldName" => $this->getName(),
                    "label" => $this->getLabel(),
                    "isExternal" => $isExternal,
                    "enabled" => $enabled,
                    "parentHidden" => ($hidden && !empty($this->parent)),
                    "parent" => $this->parent,
                    "required" => $this->isRequired(),
                    "maxLength" => 50,
                    // "fullList" => $fullList,
                    "isNewtab" => $isNewtab,
                    "linkLabel" => $linkLabel,
                    "selectedObjectId" => $selectedObjectId,
                    "selectedObject" => $selectedObject,
                    "linkUrl" => $linkUrl,
                    "info" => $this->getInfo(),
                    "blocksMode" => $this->blocksMode,
                    "searchUrl" => url("admin/content/auto-complete/".$this->contentType->getType()."/".$this->name),
                    "objectTypes" => self::OBJECT_TYPES
                ));
        }

        return $html;
    }

    public function save($model, $values)
    {
        $isExternal = isset($values['isExternal']) && $values['isExternal'] == 'true' ? true : false;
        $isNewtab = isset($values['isNewtab']) && $values['isNewtab'] == 'true' ? true : false;
        $objectId = isset($values['selectedObjectId']) ? $values['selectedObjectId'] : null;
        $contentType = null;
        if (!empty($values['selectedObjectId'])) {
            $object = WebsiteObject::where('website_object_id', $values['selectedObjectId'])->first();
            $contentType = $object != null ? $object->content_type : null;
        }
        $fieldStructure = array(
            'label' => !empty($values['label']) ? $values['label'] : '',
            'isExternal' => $isExternal,
            'isNewtab' => $isNewtab,
            'url' => $isExternal ? $values['url'] : null,
            'objectId' => !$isExternal ? $objectId : null,
            'contentType' => $contentType
        );
        $fieldName = $this->getName();
        $model->$fieldName = json_encode($fieldStructure);
    }

    public function getValidation($subField = null)
    {
        $rules = [];
        if ($this->isRequired()) {
            $rules[] = "required";
        } else {
            $rules[] = "nullable";
        }
        switch ($subField) {
            case 'label':
                if ($this->maxLabel > 0) {
                    $rules[] = "max:{$this->maxLabel}";
                }
                break;
            case 'url':
                $rules[] = "regex:/((https?:\/\/)?([\da-z\.-]+)\.([a-z]{2,6})([\/\w\.-]*)*\/?)|(#[a-zA-Z_-]+)/";
                break;
            case 'selectedObjectId':
                $rules[] = "integer";
                break;
        }

        return $rules;
    }

    public function getValidationData($copyAllLang = false)
    {
        $validation = array(
            "rules" => array(),
            "values" => array(),
            "labels" => array()
        );

        $fieldName = $this->getName();
        $fieldValue = request()->input($fieldName);

        /*
        if ($this->isMultiLanguage()) {
            foreach ($fieldValue as $lang => $langValue) {
                $fieldValue[$lang] = $langValue;
            }
        }
        */
        if ($this->isMultiLanguage()) {
            if ($copyAllLang) {
                $defaultLocale = Localization::getDefaultLocale();
                $allLanguages = Localization::getAllLanguages();
                if (!array_key_exists($defaultLocale, $fieldValue)) {
                    throw new InvalidConfigurationException("The current website doesn't have the backoffice default language");
                }

                foreach ($allLanguages as $languages) {
                    $locale = $languages->id;
                    if ($locale == $defaultLocale) {
                        continue;
                    }

                    if (empty($fieldValue[$locale]) || (empty($fieldValue[$locale]['label']) && empty($fieldValue[$locale]['url']) && empty($fieldValue[$locale]['selectedObjectId']))) {
                        $fieldValue[$locale] = $fieldValue[$defaultLocale];
                    }
                }
            }

            $languages = Localization::getSupportedLanguages();

            $labelRules = generateLangRules(
                array($fieldName => $this->getValidation('label')),
                $languages,
                'label');

            $urlRules = array();
            foreach ($languages as $lang) {
                if (isset($fieldValue[$lang->id]['isExternal']) && $fieldValue[$lang->id]['isExternal'] == 'true') {
                    $urlRules[$fieldName.'.'.$lang->id.'.url'] = $this->getValidation('url');
                } else {
                    $urlRules[$fieldName.'.'.$lang->id.'.selectedObjectId'] = $this->getValidation('selectedObjectId');
                }
            }
            $validation["rules"] = array_merge($labelRules, $urlRules);

            $labelLabel = generateLangLabels(
                $fieldName, trans('backend.link_label'), $languages, 'label');
            $urlLabel = generateLangLabels(
                $fieldName, trans('backend.link_url'), $languages, 'url');
            $isExternalLabel = generateLangLabels(
                $fieldName, trans('backend.link_object'), $languages, 'selectedObjectId');
            $validation["labels"] = array_merge($labelLabel, $urlLabel, $isExternalLabel);
        } else {
            $validation["rules"][$fieldName.'.label'] = $this->getValidation('label');
            if (isset($fieldValue['isExternal']) && $fieldValue['isExternal'] == 'true') {
                $validation["rules"][$fieldName.'.url'] = $this->getValidation('url');
            } else {
                $validation["rules"][$fieldName.'.selectedObjectId'] = $this->getValidation('selectedObjectId');
            }
            $validation["labels"][$fieldName.'.label'] = trans('backend.link_label');
            $validation["labels"][$fieldName.'.url'] = trans('backend.link_url');
            $validation["labels"][$fieldName.'.selectedObjectId'] = trans('backend.link_object');
        }

        $validation["values"][$fieldName] = $fieldValue;

        return $validation;
    }

    public static function getScript()
    {
        return array(
            "linkField" =>
                path_asset('path.backoffice.js_path').'/view/backend-link-field.js'
        );
    }

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

    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())
    {
        if (!empty($objectTypes)) {
            $this->websiteFiltered = true;
        }

        $this->objectTypes = $objectTypes;
    }

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


