<?php namespace Concore\Foundation\Models;

use Config, Image, Storage, Cache;
use Concore\Foundation\Models\Interfaces\IdentifiableInterface;
use Concore\Foundation\Models\Traits\IdentifiableTrait;
use Illuminate\Database\Eloquent\Model;

class Media extends Model implements IdentifiableInterface {
	
	use IdentifiableTrait;

	public $validation_rules = [
		'media.file' => 'required'
	];

	public $fillable = ['name','type','filename','filesize','mimetype','generated_sizes'];

	public function __construct() {
		$this->validation_rules['media.file'] .= '|max:' . app('Concore\Foundation\Services\MediaService')->maxAllowedFileSize();
		$mimes = [];
		foreach(array_flatten(setting_or_config('foundation.media.allowed_mimetypes')) as $mime) {
			if(strpos($mime, '/')) {
				list($type,$mime) = explode('/',$mime);
			}
			$mimes[] = $mime;
		}
		if (setting_or_config('foundation.media.allow_all_mimetypes', false) !== true) {
			$this->validation_rules['media.file'] .= '|mimes:' . implode(',',$mimes);
		}
	}

	public function getGeneratedSizes() {
		$sizes = explode(',',$this->generated_sizes);
		return $sizes;
	}

	protected function sizeExists($size_string) {
		return in_array($size_string, $this->getGeneratedSizes());
	}

	protected function generateSize($size_string, $size, $quality = 100, $force = false) {
		$resized_path = 'app/' . $this->type . '/' . $size_string . '/' . $this->filename;
		if(!Storage::exists($this->path)) {
			\Log::info('Base file can\'t be found...');
			return null;
		}
		if(!$force && Storage::exists($resized_path)) {
			\Log::info('Resized file exists...');
			return true;
		} else {
			$image = Image::make(Storage::get($this->path));
			$image->interlace(true); // if a JPG, encode as a progressive JPG
			if ($size !== 'original') {
				if(strpos($size, 'x') !== false) {
					list($width, $height) = explode('x',$size);
				} else {
					$width = $size;
					$height = null;
				}
				if ($width && !$height) {
					$image->widen($width);
				} else if ($height && !$width) {
					$image->heighten($height);
				} else {
					$image->fit($width, $height);
				}
			}
			\Log::info('Streaming file...');
			return Storage::disk()->put($resized_path, $image->stream(null,$quality)->detach(), setting_or_config('foundation.media.default-visibility'));
		}
	}

	public function regenerateSizes() {
		foreach($this->getGeneratedSizes() as $size) {
			$quality = null;
			$size_string = $this->getSizeString($size, $quality);
			if(strpos($size, '@') !== false) {
				list($size, $quality) = explode('@',$size);
			}
			if($this->generateSize($size_string, $size, $quality, true)) {
				$this->addSizeToDb($size_string);
			}
		}
	}

	protected function addSizeToDb($size_string) {
		$sizes_in_db = $this->getGeneratedSizes();
		if(!in_array($size_string, $sizes_in_db)) {
			$sizes_in_db[] = $size_string;
			$this->generated_sizes = implode(',',array_filter($sizes_in_db));
			$this->save();
		}
	}

	protected function getSizeString($size, $quality) {
		return ($size ?: 'original') . ($quality ? '@' . $quality : '');
	}

	public function getUrl($size = null, $quality = null, $generate_url = false, $direct_url = false) {

		if (!$generate_url || setting_or_config('filesystems.default') == 'local') {
			if($this->type === 'image') {
				if(!$size) {
					$size = 'original';
				}
				if($quality) {
					$size .= '@' . $quality;
				}
				if ($direct_url) {
					return route('image-direct',[$size, $this->filename]);
				}
				return route('image',[$size, $this->filename]);
			} else {
				if ($direct_url) {
					return route('media-direct',[$this->type, $this->filename]);
				}
				return route('media',[$this->type, $this->filename]);
			}
		}

		if($this->type == 'image' && ($size || $quality)) {
			$size_string = $this->getSizeString($size, $quality);
			if(!$this->sizeExists($size_string)) {
				\Log::info('Generating size ' . $size_string . ' for ' . $this->filename);
				if(strpos($size, '@') !== false) {
					list($size, $quality) = explode('@',$size);
				}
				if($this->generateSize($size_string, $size, $quality)) {
					$this->addSizeToDb($size_string);
				}
			}
			$path = $this->type . "/" . $size_string . '/' . $this->filename;
			if ($size_string == 'original' && !Storage::exists($path)) {
				$path = $this->type . '/' . $this->filename;
			}
			$private_url_cache_key = "media.private-urls." . $this->type . "." . $size_string . '.' . $this->filename;
		} else {
			$path = $this->type . "/" . $this->filename;
			$private_url_cache_key = "media.private-urls." . $this->type . '.' . $this->filename;
		}

		$default_config = setting_or_config('filesystems.disks.'.setting_or_config('filesystems.default'));
		$public_url = $default_config['base_url'] . '/' . $default_config['bucket'] . '/app/' . $path;

		if(setting_or_config('foundation.media.default-visibility') == 'public') {
			return $public_url;
		} else {
			$client = false;
			if(setting_or_config('filesystems.disks.s3gcs') !== null) {
				$client = Storage::disk('s3gcs')->getDriver()->getAdapter()->getClient();
			} elseif ($default_config['driver'] == 'gcs') {
				$client = Storage::disk()->getDriver()->getAdapter()->getClient();
			}
			if($client) {
				$request = $client->createRequest('GET',$default_config['bucket'] . '/app/' . $path);
				$expiry = setting_or_config('foundation.media.private-timeout');
				$url = Cache::get($private_url_cache_key);
				if(!$url) {
					$url = $client->createPresignedUrl($request, "+" . ($expiry + 1) . " minutes");
					$url = str_replace('AWSAccessKeyId', 'GoogleAccessId', $url);
					Cache::put($private_url_cache_key, $url, $expiry);
					\Log::info(Cache::get($private_url_cache_key));
				}
				return $url;
			} else {
				return $public_url;
			}
		}
	}

	public function getDirectUrl($size = null, $quality = null) {
		return $this->getUrl($size, $quality, false, true);
	}

	public function getRelativeUrl($size = null, $quality = null) {
		return $this->getUrl($size, $quality);
	}

	public function getPathAttribute() {
		return 'app/' . $this->type . "/" . $this->filename;
	}

	public function getSizePath($size_string) {
		return 'app/' . $this->type . "/" . $size_string . '/' . $this->filename;
	}
	
	public function getFileSize($format = 'b') {
		switch($format) {
			case 'b':
				return $this->filesize . 'b';
				break;
			case 'kb':
				// return ceil($this->filesize/10000) . 'kb';
				return (($this->filesize < 10000) ? 1 : round($this->filesize/10000)) . 'kb';
				break;
			case 'mb':
				// return ceil($this->filesize/1000000) . 'mb';
				return (($this->filesize < 1000000) ? 1 : round($this->filesize/1000000)) . 'mb';
				break;
			case 'gb':
				// return ceil($this->filesize/1000000000) . 'gb';
				return (($this->filesize < 1000000000) ? 1 : round($this->filesize/1000000000)) . 'gb';
				break;
		}
	}

	public function nameFromFilename() {
		return preg_replace('/([a-zA-Z])[\-\_]([a-zA-Z0-9])/','$1 $2',preg_replace('/\.[^.]+$/','',$this->filename));
	}

}