<?php

namespace App\Http\Controllers\Examples;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Http\Resources\JsonResource;
use App\Models\WidgetImage as Entity;

/**
 * Primer CRUD-a za koriscenje 'widget_images' tabele i pripadajuceg 'WidgetImage' 
 * modela.
 */
class WidgetImagesController extends Controller
{
    const SOFT_IMAGE_DELETION = 'soft';
    const HARD_IMAGE_DELETION = 'hard';

    private $imageDeletionType = self::SOFT_IMAGE_DELETION;

    /**
     * Vrati niz koji sadrzi validaciona pravila kojih mora da se pridrzava
     * 'upload'-ovana slika.
     * 
     * @return array
     */
    private function getImageValidationRules($minWidth=1024, $minHeight=768)
    {
        return ['file', 'image','max:' . config('newscms.max_image_upload_size'), 
                'mimes:jpeg,bmp,png', Rule::dimensions()->minWidth($minWidth)->minHeight($minHeight)];
    }

    /*
     * Yajrabox datatables metod
     */
    public function datatable(Request $request)
    {
        $query = Entity::query();

        return datatables($query)
            ->addColumn('actions', function ($entity) {
                return view('examples.widget_images.partials.table.actions', ['entity' => $entity]);
            })
            ->addColumn('images', function ($entity) {
                return view('examples.widget_images.partials.table.image', ['entity' => $entity, 'width' => '300px']);
            })
            ->addColumn('date', function ($entity) {
                return view('_layout.partials.table.datum', ['datum' => $entity->start_at]);
            })
            ->rawColumns(['actions', 'images', 'date'])
            ->setRowAttr([
                'id' => function($entity) {
                    return $entity->id;
                }
            ])
            ->make(true);
    }

    /**
     * Prikazi listing svih 'widget_images' slika.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('examples.widget_images.index');
    }

    /**
     * Prikazi stranicu za kreiranje nove 'widget_images' slike.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        $entity = new Entity;

        return view('examples.widget_images.create', ['entity' => $entity]);
    }

    /**
     * Sacuvaj novokreiranu sliku na HDD-u i metapodatke u
     * tabelu podataka 'widget_images'.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $data = $request->validate([
            'start_at' => ['required', 'date'],
            'image' => array_merge(['required'], $this->getImageValidationRules()),
            'title' => ['nullable', 'string', 'max:255'],
            'description' => ['nullable', 'string', 'max:1000'],
        ]);

        unset($data['image']);

        $entity = Entity::create($data);
    
        // sacuvaj sliku
        if($request->hasFile('image')) {
            $imgPublicPath = $this->saveImage($request->file('image'), $entity->id);
            if($imgPublicPath === FALSE) {
                return redirect()->back()
                                 ->withSystemError(__('Greška: Nije moguce snimanje slike.'));
            }
            $entity->fill(['image' => $imgPublicPath]);
            $entity->save();
        }

        $message = __('Unos slike je uspešno snimljen');

        return redirect()->route('examples.widget_images.index')
                         ->withSystemSuccess($message);

    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\WidgetImage  $entity
     * @return \Illuminate\Http\Response
     */
    public function edit(Entity $entity)
    {
        return view('examples.widget_images.edit', ['entity' => $entity]);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\WidgetImage  $entity
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Entity $entity)
    {
        $data = $request->validate([
            'start_at' => ['required', 'date'],
            'image' => array_merge(['nullable'], $this->getImageValidationRules()),
            'title' => ['nullable', 'string', 'max:255'],
            'description' => ['nullable', 'string', 'max:1000'],
        ]);
        unset($data['image']);

        //dd("Update image", $entity, $request->all());

        // izmeni sliku
        if($request->hasFile('image')) {
            if($entity->image) {
                $this->deleteImage($entity->image);
            }
            $imgPublicPath = $this->saveImage($request->file('image'), $entity->id);
            if($imgPublicPath === FALSE) {
                return redirect()->back()
                                 ->withSystemError(__('Greška: Nije moguce snimanje slike.'));
            }
            $data['image'] = $imgPublicPath;
        }
        
        $entity->fill($data);
        $entity->save();

        $message = __('Slika je uspešno izmenjena!');
        
        return redirect()->route('examples.widget_images.index')
                         ->withSystemSuccess($message);
    }

    /**
     * Izbrisi sliku.
     * 
     * @param  \App\Models\WidgetImage  $widgetImage
     * @return JSON|\Illuminate\Http\Response
     */
    public function delete(Request $request, Entity $entity)
    {
        $entity->delete();
        $message = __('Slika je uspešno obrisana!');

        if ($this->imageDeletionType == self::HARD_IMAGE_DELETION) {
            $this->deleteImage($entity->image);
            $entity->forceDelete();
        }
        
        if ($request->wantsJson()) {
            return JsonResource::make()->withSuccess($message);
        }
        
        return redirect()->back()
                         ->withSystemSuccess($message);

    }

    /**
     * Vrati 'string' putanje od delova putanje.
     * 
     * param variadic(string) $parts
     * 
     * @return string
     */
    private function joinToPath(...$parts)
    {
        $trimmedParts = array_map(function($el) {
            return rtrim($el, '/');
        }, $parts);
        return join('/', $trimmedParts);
    }

    /**
     * Sacuvaj sliku na HDD sa 'template'-om imena:
     * id-stavke-originalno-ime-slike-orig.jpg
     * 
     * @param UploadedFile $file         | 'file' objekat iz 'request'-a
     * @param string  $serverStoragePath | apsolutna putanja
     * @param string  $publicStoragePath | putanja gde je 'root' 'public'
     * @param integer $entityId          | ID kategorije
     * @param string  $fnameSugar        | dodatak na kraju imena slike
     * 
     * @return string
     */
    private function saveImageToHdd(
        \Illuminate\Http\UploadedFile $requestFile, 
        $serverStoragePath, 
        $publicStoragePath, 
        $entityId, 
        $fnameSugar = ''
    ) {

        $file = \Intervention\Image\Facades\Image::make($requestFile);

        // ovde izvrsi 'resize' slike ukoliko bude potrebno
        // -------------------- ##### ----------------------

        $fullFileName = \App\Models\Image::constructImageFilename($requestFile, $entityId, $fnameSugar);
        $file->save($this->joinToPath($serverStoragePath, $fullFileName));
        
        return $this->joinToPath($publicStoragePath, $fullFileName);
    }

    /**
     * Sacuvaj 'upload'-ovanu sliku na ciljnoj putanji:
     * /public/data/images/2020-07-23
     * 
     * @param \Illuminate\Http\UploadedFile $uploadedImage
     * @param integer $entityId
     * 
     * @return string|FALSE
     */
    private function saveImage(\Illuminate\Http\UploadedFile $uploadedImage, $entityId)
    {
        // formiraj putanju do slike
        $storeImagesAppPath = config('newscms.images_folder_absolute_path');
        $targetFolderName = now()->toDateString();
        $targetFolderAbsolutePath = $this->joinToPath($storeImagesAppPath, $targetFolderName);

        // kreiraj folder sa danasnjim datumom ukoliko vec ne postoji
        if( ! file_exists($targetFolderAbsolutePath) ) {
            try {
                mkdir($targetFolderAbsolutePath, 0755, TRUE);
            }
            catch (\ErrorException $e) {
                \Log::error('Greska: Prilikom kreiranja direktorijuma za sliku. '
                         . 'mkdir je vratio gresku. Putanja: ' . $targetFolderAbsolutePath
                         . ' Originalna greska: ' . $e->getMessage());
                return FALSE;
            }
        }

        // sacuvaj sliku na HDD-u
        $res = $this->saveImageToHdd($uploadedImage, $targetFolderAbsolutePath, 
                                     $targetFolderName, $entityId, '-orig');
        
        return $res;
    }

    /**
     * Izbrisi sliku sa HDD-a.
     * 
     * @param string $imgPublicPath
     * 
     * @return boolean
     */
    private function deleteImage($savedImgPath)
    {
        $storeImagesAppPath = config('newscms.images_folder_absolute_path');
        $imgAbsolutePath = $this->joinToPath($storeImagesAppPath, $savedImgPath);

        try {
            return unlink($imgAbsolutePath);
        }
        catch(\ErrorException $e) {
            \Log::error("Stara slika sa putanjom '$imgAbsolutePath' nije mogla biti izbrisana." 
                     . " unlink() poruka greske: " . $e->getMessage());
            return FALSE;
        }
    }
}
