<?php

namespace App\Libs\Backoffice\Generic\Fields;

use App\Facades\ContentTypes;
use App\Facades\RequestContext;
use App\Libs\Contracts\Backoffice\SavableField;
use App\Models\GenericBackoffice\WebsiteObject;
use Illuminate\Database\Eloquent\Model;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;

class LinkField extends BaseField implements SavableField
{

    protected $required = false;
    protected $objectTypes = [];
    protected $maxLabel = 0;

    public function __construct($config)
    {
        unset($config["validation"]);
        unset($config["preValidation"]);
        unset($config["inList"]);
        unset($config["search"]);
        unset($config["sort"]);

        parent::__construct($config);

        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 $model, $enabled = true, $hidden = false)
    {

        $fieldName = $this->getName();
        $enabled = true;
        $isExternal = false;
        $selectedObjectId = null;
        $linkUrl = "";
        $linkLabel = "";

        $query = WebsiteObject::with("objectable")
            ->whereIn("object_type", $this->getObjectTypesModelsType());

        $objects = $query->get();

        $fullList = [];

        foreach ($this->getContentTypes() as $contentType) {
            $fullList[$contentType->getModelType()] = [
                "label" => ucfirst($contentType->getLabel()),
                "list" => []
            ];
        }

        foreach ($objects as $object) {
            $fullList[$object->object_type]["list"][] = (object) [
                "id" => $object->id,
                "title" => $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()) {
            $locales = LaravelLocalization::getSupportedLocales();
            $defaultLocale = LaravelLocalization::getDefaultLocale();

            foreach ($locales as $locale => $localeData) {
                $hasErrors = false;
                $name = $fieldName."[{$locale}]";
                $id = $fieldName."_{$locale}";
                $errorKey = $fieldName.".".$locale;
                $isExternal = false;
                $selectedObjectId = null;
                $linkUrl = "";
                $linkLabel = "";

                if (!empty($errors) && !$errors->isEmpty()) {
                    if ($errors->has("{$this->getName()}.{$locale}.label") ||
                        $errors->has("{$this->getName()}.{$locale}.url") ||
                        $errors->has("{$this->getName()}.{$locale}.selectedObjectId")) {
                        $hasErrors = true;
                    }
                }

                if ($model->exists) {
                    $languageModel = $model->languages->findByLocale($locale);

                    if (!empty($languageModel)) {
                        $value = $languageModel->$fieldName;
                    }

                    if (!empty($value)) {
                        $linkLabel = $value['label'];
                        $isExternal = isset($value['isExternal']);
                        $linkUrl = $isExternal ? $value['url'] : null;
                        $selectedObjectId = !$isExternal ? $value['objectId'] : null;
                    }
                } else {
                    $isExternal = isset($postData[$locale]['isExternal']);
                }

                $html .= view(
                    "admin.generic.components.forms.link",
                    [
                        "id" => $id,
                        "errorKey" => $errorKey,
                        "hasErrors" => $hasErrors,
                        "name" => $name,
                        "label" => $this->getLabel(),
                        "language" => $locale,
                        "defaultLang" => $defaultLocale,
                        "enabled" => $enabled,
                        "parentHidden" => ($hidden && !empty($this->parent)),
                        "parent" => $this->parent,
                        "required" => $this->isRequired(),
                        "maxLength" => 50,
                        "fullList" => $fullList,
                        "hide" => ($hidden || $locale != $defaultLocale),

                        "isExternal" => $isExternal,
                        "linkLabel" => $linkLabel,
                        "selectedObjectId" => $selectedObjectId,
                        "linkUrl" => $linkUrl,
                        "info" => $this->getInfo()
                    ]);
            }
        } 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 ($model->exists) {
                $value = $model->$fieldName;

                if (!empty($value)) {
                    $linkLabel = $value['label'];
                    $isExternal = $value['isExternal'];
                    $linkUrl = $isExternal ? $value['url'] : null;
                    $selectedObjectId = !$isExternal ? $value['objectId'] : null;
                }
            }

            $html .= view(
                "admin.generic.components.forms.link",
                [
                    "id" => $this->getName(),
                    "errorKey" => $this->getName(),
                    "hasErrors" => $hasErrors,
                    "name" => $this->getName(),
                    "label" => $this->getLabel(),
                    "isExternal" => $isExternal,
                    "enabled" => $enabled,
                    "parentHidden" => ($hidden && !empty($this->parent)),
                    "parent" => $this->parent,
                    "required" => $this->isRequired(),
                    "maxLength" => 50,
                    "fullList" => $fullList,
                    "isExternal" => $isExternal,
                    "linkLabel" => $linkLabel,
                    "selectedObjectId" => $selectedObjectId,
                    "linkUrl" => $linkUrl,
                    "info" => $this->getInfo()
                ]);
        }

        return $html;
    }

    public function save(Model $model, $values)
    {
        $isExternal = isset($values['isExternal']) && $values['isExternal'] == 'true' ? true : false;
        $fieldStructure = [
            'label' => $values['label'],
            'isExternal' => $isExternal,
            'url' => $isExternal ? $values['url'] : null,
            'objectId' => !$isExternal ? $values['selectedObjectId'] : null
        ];
        $fieldName = $this->getName();
        $model->$fieldName = $fieldStructure;
    }

    public function getValidation($subField = null)
    {
        $rules = "";
        if ($this->isRequired()) {
            $rules = "required|";
        }
        switch ($subField) {
            case 'label':
                if ($this->maxLabel > 0) {
                    $rules .= "max:{$this->maxLabel}";
                }
                break;
            case 'url':
                $rules .= "url";
                break;
            case 'selectedObjectId':
                $rules .= "integer";
                break;
        }

        return $rules;
    }

    public function getValidationData($copyAllLang = false)
    {
        $validation = [
            "rules" => [],
            "values" => [],
            "labels" => []
        ];

        $fieldName = $this->getName();
        $fieldValue = request()->input($fieldName);

        if ($this->isMultiLanguage()) {
            foreach ($fieldValue as $lang => $langValue) {
                $fieldValue[$lang] = $langValue;
            }
        }

        if ($this->isMultiLanguage()) {
            $locales = LaravelLocalization::getSupportedLanguagesKeys();
            $defaultLocale = config('app.locale');

            if ($copyAllLang) {

                foreach ($locales as $locale) {
                    if ($locale == $defaultLocale) {
                        continue;
                    }

                    if (empty($fieldValue[$locale])) {
                        $fieldValue[$locale] = $fieldValue[$defaultLocale];
                    }
                }
            }


            $labelRules = generateLangRules(
                [$fieldName => $this->getValidation('label')],
                $locales,
                'label');

            $urlRules = [];
            foreach ($locales as $locale) {
                if (isset($value[$locale]['isExternal']) == 'true') {
                    $urlRules[$fieldName.'.'.$locale.'.url'] = $this->getValidation('url');
                } else {
                    $urlRules[$fieldName.'.'.$locale.'.selectedObjectId'] = $this->getValidation('selectedObjectId');
                }
            }
            $validation["rules"] = array_merge($labelRules, $urlRules);

            $labelLabel = generateLangLabels(
                $fieldName, trans('backend.link_label'), $locales, 'label');
            $urlLabel = generateLangLabels(
                $fieldName, trans('backend.link_url'), $locales, 'url');
            $isExternalLabel = generateLangLabels(
                $fieldName, trans('backend.link_object'), $locales, 'selectedObjectId');
            $validation["labels"] = array_merge($labelLabel, $urlLabel, $isExternalLabel);
        } else {
            $validation["rules"][$fieldName.'.label'] = $this->getValidation('label');
            if (isset($value['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 [
            "linkField" =>
                path_asset('path.backoffice.js_path').'/view/generic/backend-link-field.js'
        ];
    }

    public function toArray()
    {
        $array = parent::toArray();
        $array["required"] = $this->required;

        return $array;
    }

    public function getObjectTypesModelsType()
    {
        $modelsType = [];
        foreach ($this->objectTypes as $objectType) {
            $contentType = ContentTypes::find($objectType);
            $modelsType[] = $contentType->getModelType();
        }

        return $modelsType;
    }

    public function getContentTypes()
    {
        $contentTypes = [];
        foreach ($this->objectTypes as $objectType) {
            $contentType = ContentTypes::find($objectType);
            $contentTypes[] = $contentType;
        }

        return $contentTypes;
    }

    public function setObjectTypes($objectTypes = [])
    {
        if (!empty($objectTypes)) {
            $this->websiteFiltered = true;
        }

        $this->objectTypes = $objectTypes;
    }

    public function getObjectTypes()
    {
        return $this->objectTypes;
    }
}
  

