<?php

namespace Fivable\Buildable\Models;

use Fivable\Buildable\Traits\HasMetas;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
Use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;

class BuildableFile extends Model
{
    // We used to use SoftDeletes
    use HasMetas;

    /* Columns that are mass-assignable */
    protected $fillable = ['name', 'original_file_name', 'url', 'mime_type', 'file_size', 'width', 'height'];
    /* Columns to convert to Carbon */
    protected $dates = ['created_at', 'updated_at', 'deleted_at'];
    /* Accessors to automatically populate */
    protected $appends = ['metas'];


    /** Relationships
     * ----------------*/

    //TODO: Add some kind of logic for relationship to BuildableComponent through it's content?


    /** CRUD Helpers
     * ----------------*/

    /**
     * Persist an uploaded file to s3 and create BuildableFile object for it
     * @param Request $request
     * @return BuildableFile|bool
     */
    public static function createFile(Request $request)
    {
        if ($request->hasFile('uploaded_file')) {
            $uploadedFile = $request->file('uploaded_file');

            if (substr($uploadedFile->getMimeType(), 0, 5) == 'image') {
                $imageData = getimagesize($uploadedFile);
                $width = $imageData[0];
                $height = $imageData[1];
            }

            $buildableFile = BuildableFile::create([
                'name' => $request->name ?? $uploadedFile->getClientOriginalName(),
                'original_file_name' => $uploadedFile->getClientOriginalName(),
                'mime_type' => $uploadedFile->getMimeType(),
                'file_size' => $request->file('uploaded_file')->getSize(),
                'width' => $width ?? NULL,
                'height' => $height ?? NULL,
                'url' => ''
            ]);

            // $buildableFile->saveMetas($request->metas);

            return $buildableFile->putInStorage($uploadedFile);
        } else {
            return false;
        }
    }

    /**
     * Update this BuildableFile and it's s3 file if necessary
     * @param Request $request
     * @return BuildableFile
     */
    public function updateFile(Request $request) : BuildableFile
    {
        if ($request->hasFile('updated_file')) {
            $updatedFile = $request->file('updated_file');
            $this->deleteInStorage(); $this->putInStorage($updatedFile);

            if (substr($updatedFile->getMimeType(), 0, 5) == 'image') {
                $imageData = getimagesize($updatedFile);
                $width = $imageData[0];
                $height = $imageData[1];
            }

            $this->update([
                'name' => $request->name,
                'original_file_name' => $updatedFile ? $updatedFile->getClientOriginalName() : $this->original_file_name,
                'mime_type' => $updatedFile ? $updatedFile->getClientOriginalExtension() : $this->mime_type,
                'file_size' => $request->file('file')->getSize(),
                'width' => $width ?? NULL,
                'height' => $height ?? NULL,
            ]);

        } else {
            $this->update([
                'name' => $request->name,
            ]);
        }

        $this->updateMetas($request->metas);

        return $this;
    }

    /**
     * Get the string this file uses for s3 storage
     * @return string
     */
    public function getStorageNameAttribute() : string
    {
        return str_replace(' ', '',$this->id . $this->name) . '.' . $this->extension;
    }

    /**
     * Get the extension of this file
     * @return string
     */
    public function getExtensionAttribute() : string
    {
        $slashPosition = strpos($this->mime_type, '/');
        return substr($this->mime_type, $slashPosition + 1);
    }

    public function getStoragePathAttribute() : string
    {
        return $this->mime_type . '/' . $this->storage_name;
    }

    /**
     * Persist a BuildableFile's file in s3
     * @param UploadedFile $fileToStore
     * @return BuildableFile $this
     */
    public function putInStorage(UploadedFile $fileToStore) : BuildableFile
    {
        Storage::disk('s3')->putFileAs($this->mime_type, $fileToStore, $this->storage_name, ['visibility' => 'public']);
        $this->update(['url' => Storage::disk('s3')->url($this->storage_path)]);
        return $this;
    }

    /**
     * Delete this BuildableFile's s3 file
     */
    public function deleteInStorage()
    {
        Storage::disk('s3')->delete($this->storage_path);
    }

    /**
     * Retrieve the BuildableFile's s3 file
     * @return string|bool
     * @throws FileNotFoundException
     */
    public function retrieve()
    {
        if ($exists = Storage::disk('s3')->exists($this->storage_path)) {
            return Storage::disk('s3')->get($this->storage_path);
        } else {
            return false;
        }
    }

    /**
     * Retrieve all BuildableFiles' s3 files
     * @return bool|Collection
     * @throws FileNotFoundException
     */
    public static function retrieveAll()
    {
        $files = [];
        foreach (BuildableFile::all() as $file) {
            if (Storage::disk('s3')->exists($file->storage_path)) {
                array_push($files, Storage::disk('s3')->get($file->storage_path));
            }
        }
        if (empty($files)) {
            return false;
        } else {
            return collect($files);
        }
    }
}
