<?php

namespace App\Packages\v4\Capsule\Repository;

use App\Packages\Capsule\Models\Capsule;
use App\Packages\v4\Core\Repository\AbstractRepository;
use App\Packages\User\Models\User;
use Carbon\Carbon;
use DB;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

/**
 * Class CapsuleRepository
 * @package App\Packages\Capsule\Repository
 *
 * @method Capsule firstById($id)
 *
 * @property Capsule $model
 */
class CapsuleRepository extends AbstractRepository
{
    const LIMIT_READY_TO_HATCH = 100;

    public static function init()
    {
        return new CapsuleRepository(Capsule::class);
    }

    /**
     * @TODO: Is in use ???
     *
     * @param User $user
     *
     * @return Collection|Capsule[]
     */
    public function getUserPublicCapsules(User $user)
    {
        $query = $this->query()
            ->where('user_id', '=', $user->id)
            ->where('is_private', '=', false)
            ->where('is_complete', '=', true);

        return $query->get();
    }

    /**
     * @param User $user
     *
     * @return Collection|Capsule[]
     */
    public function getCapsulesLikesByUser(User $user)
    {
        $query = $this->query()
            ->leftJoin('table_capsule_like as like', 'like.capsule_id', 'table_capsule.id')
            ->where('like.user_id', '=', $user->id);

        return $query->get();
    }

    /**
     * @param User $user
     *
     * @return Collection|Capsule[]
     */
    public function getCapsulesCommentedByUser(User $user)
    {
        $query = $this->query()
            ->leftJoin('table_capsule_comment as comment', 'comment.capsule_id', 'table_capsule.id')
            ->where('comment.user_id', '=', $user->id);

        return $query->get();
    }

    /**
     * @param User $user
     *
     * @return Collection|Capsule[]
     */
    public function getCapsulesSubscribedByUser(User $user)
    {
        $query = $this->query()
            ->leftJoin('table_capsule_subscriber as subscriber', 'subscriber.capsule_id', 'table_capsule.id')
            ->where('subscriber.user_id', '=', $user->id);

        return $query->get();
    }

    /**
     * @TODO: Move to test service
     *
     * @param User $user
     *
     * @return Collection|Capsule[]
     */
    public function getUserAllCompleteCapsules(User $user)
    {
        $query = $this->query()
            ->where('user_id', '=', $user->id)
            ->where('is_complete', '=', true);

        return $query->get();
    }

    /**
     * @param User $user
     *
     * @return int
     */
    public function countUserCompleteCapsules(User $user)
    {
        return $this->query()
            ->where('user_id', '=', $user->id)
            ->where('is_complete', '=', true)
            ->count('id');
    }

    /**
     * @param $uuid
     * @return Capsule|null|object|static
     */
    public function firstByUuid($uuid)
    {
        return $this->query()
            ->where('uuid', '=', $uuid)
            ->first();
    }

    /**
     * @return Collection|static[]|Capsule[]
     */
    public function oldUnCompleteCapsules()
    {
        return $this->query()
            ->where('is_complete', '=', false)
            ->where('created_at', '<', now()->subDay())
            ->get();
    }

    /**
     * @return Collection|static[]|Capsule[]
     */
    public function trashedCapsules()
    {
        return $this->query()
            ->onlyTrashed()
            ->get();
    }

    /**
     * @param Carbon $date
     *
     * @return Collection|Capsule[]
     */
    public function readyToHatch(Carbon $date)
    {
        return $this->query()
            ->where('status', '=', [Capsule::STATUS_LOCKED])
            ->where('open_at', '<=', $date)
            ->where('is_complete', '=', 1)
            ->limit(static::LIMIT_READY_TO_HATCH)
            ->get();
    }

    /**
     * @param Carbon $date
     *
     * @return int
     */
    public function countByMonth(Carbon $date)
    {
        $year = $date->format('Y');
        $month = $date->format('m');

        return $this->query()
            ->where('is_complete', true)
            ->where('blocked', false)
            ->whereRaw("date_part('year', created_at) = '{$year}' AND date_part('month', created_at) = '{$month}'")
            ->count();
    }

    /**
     * @param Carbon $from
     * @param Carbon $to
     *
     * @return int
     */
    public function countByDateRange(Carbon $from, Carbon $to)
    {
        $from = $from->format('Y-m-d');
        $to = $to->format('Y-m-d');

        return $this->query()
            ->where('is_complete', true)
            ->where('blocked', false)
            ->whereRaw("created_at between '{$from}' AND '{$to}'")
            ->count();
    }

    /**
     * @param User $user
     *
     * @return int
     */
    public function countUserCapsulesForAdmin(User $user)
    {
        return $this->query()
            ->where('is_complete', true)
            ->where('user_id', $user->id)
            ->count();
    }

    public function querySuggestedCapsulesForSearch($user, $ignore = [])
    {
        $registered = $user->created_at->format('Y-m-d H:i:s');

        $query = $this->query()
            ->where('user_id', '!=', $user->id)
            ->where('is_private', false)
            ->where('is_complete', true)
            ->where('blocked', false)
            ->where(function($query) use ($registered) {
                /** @var Builder $query */
                $query->whereRaw("search_setting = 2 AND 
                    CASE WHEN set_suggested IS NULL THEN created_at < '{$registered}'::date
                    ELSE set_suggested < '{$registered}'::date END")
                    ->orWhere('search_setting', 1);
            })
            ->orderBy('suggested_position', 'DESC');

        if ( ! empty($ignore) ) {
            $query->whereNotIn('id', $ignore);
        }

        return $query;
    }

    /**
     * @param User $user
     * @param array $ignore
     * @param int $offset
     * @return int
     */
    public function countSuggestedCapsulesForSearch($user, $ignore = [], $offset = 0)
    {
        $query = $this->querySuggestedCapsulesForSearch($user, $ignore);

        if ($offset > 0) $query->skip($offset);

        return $query->count();
    }

    /**
     * @param User $user
     * @param array $ignore
     * @param int $limit
     * @param int $offset
     * @return Capsule[]|Collection
     */
    public function getSuggestedCapsulesForSearch($user, $ignore = [], $limit = 10, $offset = 0)
    {
        $query = $this->querySuggestedCapsulesForSearch($user, $ignore);

        if ($limit > 0) $query->limit($limit);
        if ($offset > 0) $query->skip($offset);

        return $query->get();
    }
}
