<?php

namespace Meoran\Images\Model;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Intervention\Image\Exception\NotReadableException;
use Intervention\Image\Image as InterventionImage;
use Meoran\Images\Exception\InvalidContent;
use Spatie\ImageOptimizer\OptimizerChain;

/**
 * Class Image
 * @property Image $content
 * @package App\Model
 */
class Image extends Model
{

    protected $_content;

    protected $table = 'images';

    public $fillable = [
        'filename',
        'content',
        'position',
        'created',
        'updated'
    ];
    protected $dates = ['created_at', 'updated_at'];
    protected $appends = ['url'];
    protected $hidden = [];

    public function getUrlAttribute()
    {
        $route = config('image.route');
        if (empty($route)) {
            return null;
        }
        return app('url')->to('/' . $route . '/' . $this->filename);
    }

    protected static function boot()
    {
        parent::boot();

        static::creating(function (Image $model) {
            if (empty($model->content)) {
                throw new InvalidContent("Content must be defined to save image");
            }
            if (!($model->content instanceof InterventionImage)) {
                throw new InvalidContent("Content must be an instance of Intervention\Image");
            }
            $model->savePicture();
        });

        static::updating(function (Image $model) {
            $model->savePicture();
        });

        static::deleted(function (Image $model) {
            $model->deletePicture();
        });

    }

    public function getPath()
    {
        if (empty($this->filename)) {
            return null;
        }

        return self::getAbsolutePath($this->filename);
    }

    static function getAbsolutePath($filename)
    {
        $basePath = config('image.path');

        $parts = array_slice(str_split(mb_strtolower(str_slug($filename, '')), 2), 0, 2);


        $path = $basePath . '/' . implode('/', $parts) . '/' . $filename;

        return $path;
    }

    static function generateRandomFilename()
    {
        return mb_strtolower(str_random(60));
    }

    static function sanitizeFilename($filename)
    {
        return str_slug($filename, '-');
    }

    public function setFilenameAttribute($value)
    {
        $pattern = '/[^a-z_\-\.0-9]/i';
        if (preg_match($pattern, $value)) {
            throw new \InvalidArgumentException("Invalid filename. Must be only composed only with a-z, A-Z, 0-9 and dot minus underscore");
        }
        $this->attributes['filename'] = $value;
    }

    public function fileExist()
    {
        return is_file($this->getPath());
    }

    public function generateFilename($force = false)
    {
        if ($this->filename && !$force) {
            return;
        }
        $this->filename = self::generateRandomFilename();
    }

    public function setContentAttribute($content)
    {
        $this->_content = app('image')->make($content);
    }

    public function getContentAttribute($value)
    {
        if (empty($this->_content)) {
            try {
                $this->_content = app('image')->make($this->getPath());
            } catch (NotReadableException $e) {
                return null;
            }
        }
        return $this->_content;
    }

    protected function savePicture()
    {
        if (empty($this->content)) {
            return true;
        }
        $this->generateFilename();
        return $this->saveContent();
    }

    protected function saveContent()
    {
        if (empty($this->content)) {
            throw new \InvalidArgumentException("Content is Empty");
        }
        $path = $this->getPath();
        $dir = dirname($path);
        if (!is_dir($dir)) {
            mkdir($dir, 0775, true);
        }
        $res = $this->content->save($path);
        app(OptimizerChain::class)->optimize($path);
        return $res;
    }

    protected function deletePicture()
    {
        $path = $this->getPath();
        if (is_file($path)) {
            return unlink($path);
        }
        return true;
    }

    /**
     * @param Model $class
     * @param $relationName
     * @return MorphToMany
     */
    public static function createRelation(Model $class, $relationName)
    {

        $instance = $class->newRelatedInstance(self::class);

        $foreignKey = 'relation_id';
        $relatedKey = 'image_id';
        $name = 'relation';
        $table = 'associate_images';
        $inverse = false;

        $relation = new MorphToMany(
            $instance->newQuery(), $class, $name, $table,
            $foreignKey, $relatedKey, $relationName, $inverse
        );
        $relation->withPivot('position');

        return $relation;
    }

    public function toArray()
    {
        $attributes = parent::toArray();

        return $attributes;
    }
}