<?php

namespace App\Helpers;

class RecentItems
{

    private $limit = 1000;
    public $store_key = 'recent';
    public $model;
    public $model_with = [];
    private $store_driver;
    private $all = null;
    public static $instance;

    public function __construct()
    {
        $this->store_driver = session();
    }

    /**
     *
     * @return RecentItems
     */
    public static function instance()
    {
        return static::$instance ? static::$instance : static::$instance = new static();
    }

    public function all($except = null)
    {
        $data = $this->store_driver->get($this->store_key);
        // filter items
        if ($except && $data) {
            return $data->filter(function($item) use ($except) {
                return $item != $except;
            });
        }
        return $data ? $data : collect();
    }

    public function add($item)
    {
        $items = $this->all();
        if (!$items->contains($item)) {
            $items = $items->prepend($item)->slice(0, $this->limit);
        } else {
            // put this item on the top.
            $items = $items->sort(function($a, $b) use ($item) {
                return $b === $item ? 1 : 0;
            });
        }

        $this->store_driver->put($this->store_key, $items);
    }

    public function remove($item)
    {
        $items = $this->all();
        $items = $items->filter(function($value) use ($item) {
            return $value != $item;
        });
        $this->store_driver->put($this->store_key, $items);
    }

    public function count() {
        return $this->all()->count();
    }

    public function contains($item)
    {
        if ($this->all === null) {
            $this->all = $this->all();
        }

        return $this->all->contains($item);
    }

    public function toggle($item)
    {
        if ($this->contains($item)) {
            $this->remove($item);
            return false;
        }
        $this->add($item);
        return true;
    }

    public function clear()
    {
        $this->store_driver->forget($this->store_key);
    }

    /**
     * Returns a Eloquent collection or an empty collection.
     *
     * @param type $except
     * @return type
     * @throws \Exception
     */
    public function allWithDB($except = null)
    {
        if (!$this->model) {
            throw new \Exception('Model must be not null');
        }

        // we cast evertyhing to int to prevent possible SQL injection
        $items_filtered = $this->all($except ? $except->id : $except)->map(function($item) {
            return (int) $item;
        });

        // if nothing left, just retrun the empty collectin!
        if (!$items_filtered->count()) {
            return $items_filtered;
        }
        // execute the eloquent query
        return $this->model::with($this->model_with)
            ->whereIn('id', $items_filtered)
            ->orderByRaw("FIELD(id,{$items_filtered->implode(',')})")
            ->get();
    }

}
