<?php

namespace App\Http\Controllers\Frontend;

use App\Http\Controllers\Controller;
use Facades\Repositories\DeviceRepo;
use Facades\Repositories\UserRepo;
use Illuminate\Support\Facades\Input;
use Tobuli\Entities\Device;
use Tobuli\Entities\DeviceCamera;
use Tobuli\Entities\File\DeviceMedia;
use Tobuli\Entities\File\DeviceCameraMedia;
use Facades\Repositories\DeviceCameraRepo;
use App\Exceptions\ResourseNotFoundException;
use Illuminate\Support\Facades\File;
use Formatter;

class DeviceMediaController extends Controller
{
    /**
     * Create view of media.
     *
     * @return array|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function create()
    {
        $search_input = Input::all();

        $deviceCollection = DeviceRepo::searchAndPaginateSimple($search_input, 'name', 'asc', 15, [$this->user->id]);

        return view('front::DeviceMedia.create')->with(compact('deviceCollection'));
    }

    public function getImages($device_id)
    {
        $device = UserRepo::getDevice($this->user->id, $device_id);
        $this->checkException('camera', 'view');
        $this->checkException('devices', 'show', $device);

        try {
            $images = DeviceCameraMedia::setEntity($device)->orderByDate('desc')->paginate(15);
        } catch (ResourseNotFoundException $e) {
            $images = [];
        }

        if ($this->api)
            return response()->json(['success' => true, 'data' => $images]);

        return view('front::DeviceMedia.images',
            [
                'images' => $images,
                'deviceId' => $device_id,
            ]
        );
    }

    public function getImage($device_id, $filename)
    {
        $device = UserRepo::getDevice($this->user->id, $device_id);

        $this->checkException('devices', 'show', $device);
        $this->checkException('camera', 'view');

        $image = DeviceMedia::setEntity($device)->find($filename);

        if ( ! $image) {
            throw new ResourseNotFoundException('front.image');
        }

        $item = $this->objectForMapDisplay($device, $image);

        if ($this->api)
            return response()->json(['success' => true, 'item' => $item, 'image' => $image->toArray()]);

        return view('front::DeviceMedia.image', [
            'image' => $image,
            'item' => $item,
            'camera_id' => 0,
        ]);
    }

    public function getFile($device_id, $filename)
    {
        $device = UserRepo::getDevice($this->user->id, $device_id);

        $this->checkException('devices', 'show', $device);
        $this->checkException('camera', 'view');

        $image = DeviceMedia::setEntity($device)->find($filename);

        if ( ! $image) {
            throw new ResourseNotFoundException('front.image');
        }

        $path = $image->path;

        if ( ! $image->isImage()) {
            return response()->download($path);
        }

        $file = File::get($path);
        $type = File::mimeType($path);

        return response($file, 200)->header("Content-Type", $type);
    }

    public function getCameraFile($camera_id, $filename)
    {
        $camera = DeviceCamera::find($camera_id);

        $this->checkException('camera', 'show', $camera);

        $image = DeviceCameraMedia::setEntity($camera)->find($filename);

        if ( ! $image) {
            throw new ResourseNotFoundException('front.image');
        }

        $path = $image->path;

        if ( ! $image->isImage()) {
            return response()->download($path);
        }

        $file = File::get($path);
        $type = File::mimeType($path);

        return response($file, 200)->header("Content-Type", $type);
    }

    public function remove($device_id, $filename)
    {
        $image = null;
        $device = UserRepo::getDevice($this->user->id, $device_id);

        $this->checkException('devices', 'show', $device);
        $this->checkException('camera', 'remove');

        $image = DeviceMedia::setEntity($device)->find($filename);

        if ($image && $image->delete()) {
            return response()->json(['success' => true]);
        }

        return response()->json(['success' => false]);
    }

    public function download($device_id, $filename)
    {
        $image = null;
        $device = UserRepo::getDevice($this->user->id, $device_id);

        $this->checkException('devices', 'show', $device);
        $this->checkException('camera', 'view');

        $image = DeviceMedia::setEntity($device)->find($filename);

        if ( ! $image) {
            throw new ResourseNotFoundException('front.image');
        }

        return response()->download($image->path);
    }

    private function objectForMapDisplay($device, $image)
    {
        if (isset($image)) {
            $closest_position = $device->positions()
                ->orderByRaw("abs(TIMESTAMPDIFF(second, time, '" . $image->created_at . "')) ASC")
                ->first();
        }

        $tail_coords = [];

        if (isset($closest_position)) {
            $tail_collection = $device->positions()
                ->where('id', '<', $closest_position->id)
                ->where('distance', '>', 0.02)
                ->orderBy('time', 'DESC')
                ->orderBy('id', 'DESC')
                ->take(10)
                ->get();

            foreach ($tail_collection as $tail) {
                $tail_coords[] = ['lat' => (string)$tail->latitude, 'lng' => (string)$tail->longitude];
            }
        }

        $item = new \stdClass();
        $item->org_id = $device->id;
        $item->id = null;
        $item->tail = $tail_coords;
        $item->tail_color = $device->tail_color;
        $item->name = $device->name;
        $item->speed = $closest_position->speed ?? '';
        $item->course = $closest_position->course ?? '';
        $item->lat = (string)($closest_position->latitude ?? '');
        $item->lng = (string)($closest_position->longitude ?? '');
        $item->altitude = $closest_position->altitude ?? '';
        $item->time = $closest_position ? Formatter::time()->human($closest_position->time) : '';
        $item->timestamp = $closest_position ? strtotime($closest_position->time) : null;
        $item->online = $device->getStatus();

        return $item;
    }
}
