<?php

namespace App\Libs\Backoffice\Fields;

use App\Http\Resources\MediaItemResource;
use App\Libs\Backoffice\ContentType;
use App\Libs\Backoffice\Contracts\PostSavableField;
use App\Libs\Backoffice\Contracts\SearchableField;
use App\Libs\Backoffice\Contracts\SavableField;
use App\Libs\Backoffice\Exceptions\InvalidConfigurationException;
use App\Models\Backoffice\MediaItem;
use App\Models\Backoffice\MediaItemReference;
use App\Models\Backoffice\Support\ContentTypeModel;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;

class MediaPickerField extends BaseField implements SavableField, SearchableField, PostSavableField
{
    protected $websiteFilter = false;
    protected $maxSize = 0;
    protected $minSize = 0;
    protected $multiple = false;
    protected $thumbnailSizes = array();
    protected $relatedContentType = false;
    protected $mediaType = false;
    protected $allowed = false;
    protected $isFullscreen = false;
    protected $baseFolder = 'default';

    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["maxSize"])) {
            $this->maxSize = $config["maxSize"];
        }

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

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

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

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

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

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

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

        if (!empty($config['baseFolder'])) {
            $this->baseFolder = $config['baseFolder'];
        }
        if (!array_key_exists($this->baseFolder, config('media.base_folders', []))) {
            throw new InvalidConfigurationException("Base folder '$this->baseFolder' not found in config/media.php");
        }
    }

    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 getAllowed() {
        return $this->allowed;
    }

    public function setAllowed($allowed) {
        $this->allowed = $allowed;
    }

    public function getIsFullscreen() {
        return $this->isFullscreen;
    }

    public function getBaseFolder() {
        return $this->baseFolder;
    }

    public function setIsFullscreen($isFullscreen) {
        $this->isFullscreen = $isFullscreen;
    }

    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)
    {
        $fieldName = $this->getName();
        $mediaItems = [];
        $value = [];

        if ($this->isMultiLanguage()) {
            $locales = LaravelLocalization::getSupportedLocales();
            $postData = request()->old($this->getName());
            foreach ($locales as $locale => $localeData) {
                $mediaItems[$locale] = [];
                $value[$locale] = [];

                if (!empty($postData)) {
                    $ids = json_decode($postData[$locale]);
                    if (sizeof($ids) > 0) {
                        $idsString = implode(',', $ids);
                        $mediaItems[$locale] = MediaItem::whereIn('id', $ids)
                            ->orderByRaw(DB::raw("FIELD(id, $idsString)"))
                            ->get();
                    }
                } else {
                    if ($model->exists) {
                        if ($this->multiple) {
                            $query = $model->$fieldName()->wherePivot("language_id", $locale)
                                ->orderBy($model->$fieldName()->getTable().'.position', 'asc');
                            $mediaItemsLangs = $query->get();
                            foreach ($mediaItemsLangs as $mediaItem) {
                                $mediaItems[$locale][] = new MediaItemResource($mediaItem);
                                $value[$locale][] = $mediaItem->id;
                            }
                        } else {
                            $modelLang = $model->languages->findByLocale($locale);
                            $keyFieldName = $modelLang->$fieldName()->getForeignKeyName();
                            if ($modelLang->$keyFieldName) {
                                $mediaItem = MediaItem::find($modelLang->$keyFieldName);
                                $mediaItems[$locale][] = new MediaItemResource($mediaItem);
                                $value[$locale][] = $mediaItem->id;
                            }
                        }
                    }
                }
            }
        } 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[] = new MediaItemResource($model->$fieldName);
                            $value[] = $mediaItems[0]->id;
                        }
                    } else {
                        $items = $model->$fieldName()->orderBy('position', 'asc')->get();

                        foreach ($items as $mediaItem) {
                            $mediaItems[] = new MediaItemResource($mediaItem);
                            $value[] = $mediaItem->id;
                        }
                    }
                }
            }
        }

        return [
            'id' => $this->getName(),
            'name' => $this->getName(),
            'type' => ucfirst($this->getType()),
            'label' => $this->getLabel(),
            'mediaType' => $this->getMediaType(),
            'mediaItems' => $mediaItems,
            'value' => $value,
            'multiple' => $this->multiple,
            'minSize' => $this->minSize,
            'maxSize' => $this->maxSize,
            'isMultilanguage' => $this->isMultiLanguage(),
            'isFullscreen' => $this->isFullscreen,
            'baseFolder' => $this->baseFolder,
            'hide' => $hidden,
            'enabled' => $enabled,
            'relatedContentType' => $this->relatedContentType,
            'parentHidden' => $hidden,
            'conditions' => $this->conditions,
            'info' => $this->getInfo()
        ];
    }

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

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

            $defaultLocale = config('app.locale');
            $locales = LaravelLocalization::getSupportedLanguagesKeys();

            if ($copyAllLang) {
                foreach ($locales as $locale) {
                    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()) {
                $validation["rules"] = generateLangRules(
                    array($fieldName => $rules),
                    $locales);

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

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

    public function postSave(ContentTypeModel $model, ContentType $contentType, mixed $values = null)
    {
        $this->syncMediaReferences($model, $values);
    }

    protected function syncMediaReferences($model, $mediaIds)
    {
        DB::beginTransaction();
        try {
            $wo = $model->websites->first();
            MediaItemReference::where('website_object_id', $wo->website_object_id)
                ->where('field_name', $this->name)
                ->delete();

            if (!empty($mediaIds)) {
                $insertData = [];
                foreach ($mediaIds as $mediaId) {
                    $insertData[] = [
                        'media_item_id' => $mediaId,
                        'website_object_id' => $wo->website_object_id,
                        'field_name' => $this->name,
                        'created_at' => now(),
                        'updated_at' => now(),
                    ];
                }
                MediaItemReference::insert($insertData);
            }
            DB::commit();
        } catch (Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

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

    protected function _saveMultipleLanguages($model, $values)
    {
        $relationName = $this->getName();
        $locales = LaravelLocalization::getSupportedLocales();
        $allMediaIds = [];
        foreach ($locales as $locale => $localeData) {
            $langValues = $values[$locale];
            $syncData = [];
            $position = 1;
            foreach ($langValues as $id) {
                $syncData[$id] = array("language_id" => $locale);
                if ($this->isMultiple()) {
                    $syncData[$id]["position"] = $position;
                    $position = $position + 1;
                }
            }
            $model->$relationName()->wherePivot("language_id", $locale)->sync($syncData);
            $allMediaIds = array_merge($allMediaIds, $langValues);
        }
    }

    protected function _saveSingleMultipleLanguages($model, $values)
    {
        $relationName = $this->getName();
        $locales = LaravelLocalization::getSupportedLocales();
        $allMediaIds = [];
        foreach ($locales as $locale => $localeData) {
            $langValue = $values[$locale];
            $modelLang = $model->languages->findByLocale($locale);
            $keyName = $modelLang->$relationName()->getQualifiedForeignKeyName();
            if (!empty($langValue)) {
                $modelLang->$keyName = $langValue[0];
                $allMediaIds[] = $langValue[0];
            } else {
                $modelLang->$keyName = null;
            }
            $modelLang->save();
        }
    }

    protected function _saveSingleLanguage($model, $values)
    {
        $relationName = $this->getName();
        $syncData = array();
        $position = 1;
        foreach ($values as $position => $mediaItem) {
            $id = $mediaItem;
            $syncData[$id] = ["position" => $position];
            $position = $position + 1;
        }
        $model->$relationName()->sync($syncData);
    }

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

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

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

        if (!empty($model->$fkName)) {
            $languages = LaravelLocalization::getSupportedLocales();

            foreach ($languages as $language) {
                $searchData[$language] = $model->$fkName;
            }
        }
        return $searchData;
    }

    public function toArray()
    {
        $array = parent::toArray();
        return $array;
    }
}
