<?php

namespace App\Libs\Backoffice\Generic\Fields;

use App\Libs\Contracts\Backoffice\DuplicatableField;
use App\Libs\Contracts\Backoffice\SavableField;
use App\Libs\Contracts\Backoffice\SearchableField;
use App\Libs\Exception\InvalidConfigurationException;
use App\Libs\Facades\Localization;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;
use MediaItem;

class MediaPickerField extends BaseField implements SavableField, SearchableField, DuplicatableField
{
    protected $websiteFilter = false;
    protected $maxSize = false;
    protected $minSize = 0;
    protected $multiple = false;
    // protected $thumbnailSizes = array();
    protected $relatedContentType = false;

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

        parent::__construct($config);

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

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

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

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

        if (!empty($config["multiple"])) {
            $this->multiple = $config["multiple"];
        }
        /*
        if (!empty($config["thumbnailSizes"])) {
            $this->thumbnailSizes = $config["thumbnailSizes"];
        }
        */
        if (!empty($config["relatedContentType"])) {
            $this->relatedContentType = $config["relatedContentType"];
        }

        if ($this->multiple || $this->multiLanguage) {
            $this->relationField = true;
        }
    }

    public function getMediaType()
    {
        return $this->mediaType;
    }

    public function setMediaType($mediaType)
    {
        $this->mediaType = $mediaType;
    }

    public function isMultiple()
    {
        return $this->multiple;
    }

    public function setMultiple($multiple)
    {
        $this->multiple = $multiple;
    }

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

        if ($this->minSize > 0) {
            $rules .= "|required|min:".$this->minSize;
        }

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

        return $rules;
    }

    public function toForm($model, $enabled = true, $hidden = false)
    {
        $fieldName = $this->getName();
        $mediaItems = [];
        $html = "";

        if ($this->isMultiLanguage()) {
            $languages = Localization::getSupportedLanguages();
            $defaultLang = Localization::getDefaultLocale();
            $postData = request()->old($this->getName());
            foreach ($languages as $language) {
                $name = $fieldName."[{$language->id}]";
                $id = $fieldName."_{$language->id}";
                $errorKey = $fieldName.".".$language->id;
                $value = null;
                $mediaItems = [];

                if (!empty($postData)) {
                    $ids = json_decode($postData[$language->id]);
                    if (sizeof($ids) > 0) {
                        $idsString = implode(',', $ids);
                        $mediaItems = MediaItem::whereIn('id', $ids)
                            ->orderByRaw(DB::raw("FIELD(id, $idsString)"))
                            ->get();
                    }
                } else {
                    if ($model->exists) {
                        $relation = $model->$fieldName();
                        $query = $model->$fieldName()->wherePivot("language_id", $language->id);
                        if ($this->multiple) {
                            $query->orderBy($model->$fieldName()->getTable().'.position', 'asc');
                        }
                        $mediaItemsLangs = $query->get();
                        if (!$this->multiple) {
                            if (!$mediaItemsLangs->isEmpty()) {
                                $mediaItems[] = $mediaItemsLangs->first();
                            }
                        } else {
                            foreach ($mediaItemsLangs as $mediaItem) {
                                $mediaItems[] = $mediaItem;
                            }
                        }
                    }
                }

                $html .= view(
                    "admin.generic.components.forms.mediapicker",
                    array(
                        "id" => $id,
                        "name" => $name,
                        "fieldName" => $fieldName,
                        "errorKey" => $errorKey,
                        "label" => $this->getLabel(),
                        "mediaType" => $this->getMediaType(),
                        "mediaItems" => $mediaItems,
                        "multiple" => $this->multiple,
                        "minSize" => $this->minSize,
                        "maxSize" => $this->maxSize,
                        "language" => $language->id,
                        "languages" => $languages,
                        "defaultLang" => $defaultLang,
                        "hide" => ($hidden || $language->id != $defaultLang),
                        "enabled" => $enabled,
                        "relatedContentType" => $this->relatedContentType,
                        "parentHidden" => ($hidden && !empty($this->parent)),
                        "parent" => $this->parent,
                        "info" => $this->getInfo(),
                        "blocksMode" => $this->blocksMode,
                    ));
            }
        } else {
            $postData = request()->old($this->getName());
            if (!empty($postData)) {
                $ids = json_decode($postData);
                if (sizeof($ids) > 0) {
                    $idsString = implode(',', $ids);
                    $mediaItems = MediaItem::whereIn('id', $ids)
                        ->orderByRaw(DB::raw("FIELD(id, $idsString)"))
                        ->get();
                }
            } else {
                if ($model->exists) {
                    if (!$this->multiple) {
                        if ($model->$fieldName) {
                            $mediaItems[] = $model->$fieldName;
                        }
                    } else {
                        $items = $model->$fieldName()->orderBy('position', 'asc')->get();
                        foreach ($items as $mediaItem) {
                            $mediaItems[] = $mediaItem;
                        }
                    }
                }
            }

            $html .= view(
                "admin.generic.components.forms.mediapicker",
                array(
                    "id" => $this->getName(),
                    "name" => $this->getName(),
                    "fieldName" => $this->getName(),
                    "errorKey" => $this->getName(),
                    "label" => $this->getLabel(),
                    "mediaType" => $this->getMediaType(),
                    "mediaItems" => $mediaItems,
                    "multiple" => $this->multiple,
                    "minSize" => $this->minSize,
                    "maxSize" => $this->maxSize,
                    "hide" => $hidden,
                    "enabled" => $enabled,
                    "relatedContentType" => $this->relatedContentType,
                    "parentHidden" => ($hidden && !empty($this->parent)),
                    "parent" => $this->parent,
                    "info" => $this->getInfo(),
                    "blocksMode" => $this->blocksMode,
                ));
        }
        return $html;
    }

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

        $fieldName = $this->getName();
        $value = request()->input($fieldName);
        if ($this->isMultiLanguage()) {
            foreach ($value as $lang => $langValue) {
                $value[$lang] = json_decode($langValue, true);
            }

            if ($copyAllLang) {
                $defaultLocale = Localization::getDefaultLocale();
                $allLanguages = Localization::getAllLanguages();
                if (!array_key_exists($defaultLocale, $value)) {
                    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($value[$locale])) {
                        $value[$locale] = $value[$defaultLocale];
                    }
                }
            }

        } else {
            $value = json_decode($value, true);
        }

        $rules = $this->getValidation();
        if (!empty($rules)) {
            if ($this->isMultiLanguage()) {
                $languages = Localization::getSupportedLanguages();
                $validation["rules"] = generateLangRules(
                    array($fieldName => $rules),
                    $languages);

                $validation["labels"] = generateLangLabels(
                    $fieldName, $this->getLabel(), $languages);
            } else {
                $validation["rules"][$fieldName] = $this->getValidation();
                $validation["labels"][$fieldName] = $this->getLabel();
            }
        }
        $validation["values"][$fieldName] = $value;
        return $validation;
    }

    public function save($model, $values)
    {
        if ($this->isMultiLanguage()) {
            $this->_saveMultipleLanguages($model, $values);
        } else {
            if ($this->isRelationField()) {
                $this->_saveSingleLanguage($model, $values);
            } else {
                $this->_saveSingle($model, $values);
            }
        }
    }

    protected function _saveSingle($model, $value)
    {
        $fieldName = $this->getName();
        $fkName = $model->$fieldName()->getForeignKeyName();
        $model->$fkName = empty($value) ? null : $value[0];
        /*
        if (!empty($value)) {
            $this->_generateThumbnails($value[0]);
        }
        */
    }

    /*
    protected function _generateThumbnails($mediaItemId)
    {
        if (sizeof($this->thumbnailSizes) == 0) {
            return;
        }
        $mediaItem = MediaItem::find($mediaItemId);

        if (empty($mediaItem) || $mediaItem->media_type != MediaItem::MEDIA_TYPE_IMAGE) {
            return;
        }

        foreach ($this->thumbnailSizes as $size) {
            if (!isset($size["name"]) || empty($size["width"]) || empty($size["width"])) {
                throw new InvalidConfigurationException("All the sizes for generic backoffice fields of type 'image' must have a name, width and height in the configuration");
            }
            $destinationPath = config('path.internal.thumbs');
            $fileName = $mediaItem->filename;
            $thumbFilename = getFileNameSize("{$destinationPath}/{$fileName}", $size["name"]);

            $originalImage = Storage::path(config('path.internal.media').'/'.$fileName);

            if (Storage::has($thumbFilename)) {
                continue;
            }

            $quality = 90;
            if ($size["width"] > 1000) {
                $quality = 75;
            } else {
                if ($size["width"] > 600) {
                    $quality = 80;
                }
            }

            switch ($size["type"]) {
                case "fit":
                    Image::make($originalImage)
                        ->fit($size["width"], $size["height"])
                        ->save(Storage::path($thumbFilename), $quality);
                    break;
                case "resize":
                    if (!isset($size["keepRatio"]) || $size["keepRatio"] === true) {
                        Image::make($originalImage)
                            ->resize($size["width"], $size["height"], function ($constraint) {
                                $constraint->aspectRatio();
                            })
                            ->resizeCanvas($size["width"], $size["height"])
                            ->save(Storage::path($thumbFilename), $quality);
                    } else {
                        Image::make($originalImage)
                            ->resize($size["width"], $size["height"])
                            ->save(Storage::path($thumbFilename), $quality);
                    }
                    break;
                case "resize_noup":
                    Image::make($originalImage)
                        ->resize($size["width"], null, function ($constraint) {
                            $constraint->aspectRatio();
                            $constraint->upsize();
                        })->save(Storage::path($thumbFilename), $quality);
                    break;
                default:
                    throw new InvalidConfigurationException("The types allowed for for generic backoffice fields of type 'image' are fit or resize in the configuration");
            }
        }
    }
    */

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

        $languages = Localization::getSupportedLanguages();
        foreach ($languages as $language) {
            $langValues = $values[$language->id];
            $syncData = array();
            $position = 1;

            foreach ($langValues as $id) {
                $syncData[$id] = array("language_id" => $language->id);

                if ($this->isMultiple()) {
                    $syncData[$id]["position"] = $position;
                    $position = $position + 1;
                }

                // $this->_generateThumbnails($id);
            }

            $model->$relationName()->wherePivot("language_id", $language->id)->sync($syncData);
        }
    }

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

        $syncData = array();
        $position = 1;
        foreach ($values as $id) {
            $syncData[$id] = array("position" => $position);
            $position = $position + 1;

            // $this->_generateThumbnails($id);
        }
        $model->$relationName()->sync($syncData);
    }

    public function getSearchStructure($model, $view = false)
    {
        $searchData = array();

        if ($this->isMultiLanguage() || $this->isRelationField()) {
            return $searchData;
        }

        $fieldName = $this->getName();
        $fkName = $model->$fieldName()->getForeignKeyName();

        if (!empty($model->$fkName)) {
            $languages = Localization::getSupportedLanguages();

            foreach ($languages as $language) {

                $searchData[$language->id] = $model->$fkName;
            }
        }

        return $searchData;
    }

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

    public static function getScript()
    {
        return array(
            "mediaPicker" =>
                path_asset('path.backoffice.js_path').'/view/backend-media-picker.js'
        );

    }

    public function duplicate($sourceModel, $model)
    {
        $relationName = $this->getName();

        if (!$this->isRelationField()) {
            // Single, belongs to relation
            $fkName = $model->$relationName()->getForeignKeyName();
            $model->$fkName = $sourceModel->$fkName;

        } else {
            $syncData = [];
            if ($this->isMultiLanguage()) {
                $languages = Localization::getSupportedLanguages();
                foreach ($languages as $language) {
                    $query = $sourceModel->$relationName()->wherePivot("language_id", $language->id);

                    if ($this->multiple) {
                        $query->orderBy($sourceModel->$relationName()->getTable().'.position', 'asc');
                    }
                    $mediaItemsLangs = $query->get();
                    $position = 1;
                    foreach ($mediaItemsLangs as $mediaItem) {
                        $pivotContent = ["language_id" => $language->id];
                        if ($this->multiple) {
                            $pivotContent['position'] = $position;
                        }
                        $syncData[$mediaItem->id] = $pivotContent;
                        $position ++;
                    }
                }
            } else {
                $items = $sourceModel->$relationName()->orderBy('position')->get();
                foreach ($items as $i => $mediaItem) {
                    $syncData[$mediaItem->id] = array("position" => $i);
                }
            }

            $model->$relationName()->sync($syncData);
        }
    }
}
