<?php namespace Eae\Backoffice\Generic\Fields;

use Config;
use DB;
use Eae\Database\Eloquent\Relations\BelongsToManyWebsite;
use Eae\Support\Contracts\SavableFieldInterface;
use Eae\Support\Contracts\SearchableFieldInterface;
use Illuminate\Database\Eloquent\Builder;
use Image;
use Input;
use LaravelLocalization;
use MediaItem;
use View;

class MediaPickerField extends BaseField implements SavableFieldInterface, SearchableFieldInterface
{
  protected $websiteFilter = FALSE;
  protected $maxSize = FALSE;
  protected $minSize = 0;
  protected $multiple = FALSE;
  protected $thumbnailSizes = [];
  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()) {
      $locales = LaravelLocalization::getSupportedLocales();
      $defaultLocale = LaravelLocalization::getDefaultLocale();
      $postData = Input::old($this->getName());
      foreach ($locales as $locale => $localeData) {
        $name = $fieldName . "[{$locale}]";
        $id = $fieldName . "_{$locale}";
        $errorKey = $fieldName . "." . $locale;
        $value = NULL;
        $mediaItems = [];

        if (!empty($postData)) {
          $ids = json_decode($postData[ $locale ]);
          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", $locale);
          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::make(
          "admin.generic.components.forms.mediapicker",
          [
            "id"                 => $id,
            "name"               => $name,
            "errorKey"           => $errorKey,
            "label"              => $this->getLabel(),
            "mediaType"          => $this->getMediaType(),
            "mediaItems"         => $mediaItems,
            "multiple"           => $this->multiple,
            "minSize"            => $this->minSize,
            "maxSize"            => $this->maxSize,
            "language"           => $locale,
            "defaultLang"        => $defaultLocale,
            "hide"               => ($hidden || $locale != $defaultLocale),
            "enabled"            => $enabled,
            "relatedContentType" => $this->relatedContentType,
            "parentHidden"       => ($hidden && !empty($this->parent)),
            "parent"             => $this->parent,
            "info"               => $this->getInfo()
          ]);
      }
    } else {
      $postData = Input::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::make(
        "admin.generic.components.forms.mediapicker",
        [
          "id"                 => $this->getName(),
          "name"               => $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()
        ]);
    }

    return $html;
  }

  public function getValidationData($copyAllLang = FALSE)
  {
    $validation = [
      "rules"  => [],
      "values" => "",
      "labels" => []];

    $fieldName = $this->getName();
    $value = Input::get($fieldName);
    if ($this->isMultiLanguage()) {
      foreach ($value as $lang => $langValue) {
        $value[ $lang ] = json_decode($langValue, TRUE);
      }

      $defaultLocale = \Config::get('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(
          [$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, $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()->getForeignKey();
    $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::get('path.internal.thumbs');
      $fileName = $mediaItem->filename;
      $thumbFilename = getFileNameSize("{$destinationPath}/{$fileName}", $size["name"]);

      $originalImage = Config::get('path.internal.media') . '/' . $fileName;

      if (file_exists($thumbFilename)) {
        continue;
      }

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

      switch ($size["type"]) {
        case "fitCrop":
          Image::make($originalImage)
            ->fit($size["width"], $size["height"])
            ->crop($size["width"], $size["height"])
            ->save($thumbFilename, $quality);
          break;
        case "fit":
          Image::make($originalImage)
            ->fit($size["width"], $size["height"])
            ->save($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($thumbFilename, $quality);
          } else {
            Image::make($originalImage)
              ->resize($size["width"], $size["height"])
              ->save($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();

    $locales = LaravelLocalization::getSupportedLocales();
    foreach ($locales as $locale => $localeData) {
      $langValues = $values[ $locale ];
      $syncData = [];
      $position = 1;

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

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

        $this->_generateThumbnails($id);
      }

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

  }

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

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

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

  public function getSearchStructure($model, $view = FALSE)
  {
    $searchData = [];

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

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

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

      foreach ($languages as $language) {

        $searchData[ $language ] = $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 ["mediaPicker" =>
              Config::get('path.backoffice.js_path') . '/view/generic/backend-media-picker.js'];

  }
}
