<?php

namespace App\Packages\v4\Follower\Repository;

use App\Packages\v4\Core\Repository\AbstractRepository;
use App\Packages\Follower\Models\FollowerRelation;
use App\Packages\User\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

/**
 * Class FollowerRepository
 * @package App\Packages\Follower\Repository
 *
 * @property FollowerRelation $model
 */
class FollowerRepository extends AbstractRepository
{
    const LIMIT_PAGE = 20;

    public static function init()
    {
        return new FollowerRepository(FollowerRelation::class);
    }

    /**
     * @return Builder
     */
    public function baseActiveRelations()
    {
        return $this->query()->where('status', true);
    }

    /**
     * @return Builder
     */
    public function baseInactiveRelations()
    {
        return $this->query()->where('status', false);
    }

    /**
     * @param $user
     * @param $follower
     * @return Builder|Model|object|null
     */
    public function getFollowerRow($user, $follower)
    {
        return $this->query()
            ->where('user_id', $user->id)
            ->where('follower_id', $follower->id)
            ->first();
    }

    /**
     * @param $user
     * @param $follower
     * @return Builder|FollowerRelation|object|null
     */
    public function getActiveFollowerRow($user, $follower)
    {
        return $this->baseActiveRelations()
            ->where('user_id', $user->id)
            ->where('follower_id', $follower->id)
            ->first();
    }

    public function isInvited($user, $follower)
    {
        $row = $this->getFollowerRow($user, $follower);

        if ( ! $row || $row->status ) return false;
        return true;
    }

    /**
     * @param User $user
     * @param User $follower
     * @return bool
     */
    public function isFollower($user, $follower)
    {
        $check = $this->getActiveFollowerRow($user, $follower);

        return (bool) $check;
    }

    /**
     * @param User $user
     * @param User $following
     * @return bool
     */
    public function isFollowing($user, $following)
    {
        $check = $this->getActiveFollowerRow($following, $user);

        return (bool) $check;
    }

    /**
     * @param User $user
     * @return bool
     */
    public function acceptAllPending($user)
    {
        $this->query()
            ->where('user_id', $user->id)
            ->where('status', false)
            ->update(['status' => true]);
        return true;
    }

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

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

    /**
     * @param User $user
     * @return int
     */
    public function countUserFollowing($user)
    {
        return $this->baseActiveRelations()
            ->where('follower_id', $user->id)
            ->count();
    }

    public function newUserFollowersExists($user)
    {
        return $this->baseActiveRelations()
            ->where('user_id', $user->id)
            ->where('updated_at', '>', $user->last_follower_seen)
            ->count();
    }

    public function newConfirmationFollowersExists($user)
    {
        return $this->baseInactiveRelations()
            ->where('user_id', $user->id)
            ->where('updated_at', '>', $user->last_follower_confirmation_seen)
            ->count();
    }

    /**
     * @param User $user
     * @param array $params
     * @return Builder
     */
    public function baseUserFollowers($user, $params = [])
    {
        $query = $this->baseActiveRelations()
            ->leftJoin(
                'table_user as user',
                'user.id',
                '=',
                'table_follower_relation.follower_id'
            )
            ->where('table_follower_relation.user_id', $user->id)
            ->whereNotNull('user.nickname')
            ->where('user.nickname', '!=', '');

        if ( isset($params['nickname']) && ! empty($params['nickname']) ) {
            $nickname = mb_strtolower($params['nickname']);
            $query->whereRaw("LOWER(\"user\".\"nickname\") LIKE ? ", ["{$nickname}%"]);
        }

        return $query;
    }

    /**
     * @param User $user
     * @param array $params
     * @return Builder
     */
    public function baseUserFollowing($user, $params = [])
    {
        $query = $this->baseActiveRelations()
            ->leftJoin(
                'table_user as user',
                'user.id',
                '=',
                'table_follower_relation.user_id'
            )
            ->where('table_follower_relation.follower_id', $user->id)
            ->where('user.id', '!=', $user->id)
            ->whereNotNull('user.nickname')
            ->where('user.nickname', '!=', '');

        if ( isset($params['nickname']) && ! empty($params['nickname']) ) {
            $nickname = mb_strtolower($params['nickname']);
            $query->whereRaw("LOWER(\"user\".\"nickname\") LIKE ?", ["{$nickname}%"]);
        }

        return $query;
    }

    public function baseWaitConfirmation($user, $params = [])
    {
        $query = $this->baseInactiveRelations()
            ->leftJoin(
                'table_user as user',
                'user.id',
                '=',
                'table_follower_relation.follower_id'
            )
            ->where('table_follower_relation.user_id', $user->id)
            ->whereNotNull('user.nickname')
            ->where('user.nickname', '!=', '');

        if ( isset($params['nickname']) && ! empty($params['nickname']) ) {
            $nickname = mb_strtolower($params['nickname']);
            $query->whereRaw("LOWER(\"user\".\"nickname\") LIKE ?", ["{$nickname}%"]);
        }

        return $query;
    }

    /**
     * @param User $user
     * @param string $search
     * @param int $page
     * @return Builder[]|Collection
     */
    public function getPaginatedUserFollowers($user, $search = '', $page = 1)
    {
        $query = $this->baseUserFollowers(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->select('user.*')
        ->orderBy('user.nickname', 'DESC');

        $query->skip(($page - 1) * static::LIMIT_PAGE)->take(static::LIMIT_PAGE);

        return $query->get();
    }

    /**
     * @param User $user
     * @param string $search
     * @param int $page
     * @return Builder[]|Collection
     */
    public function getPaginatedUserFollowing($user, $search = '', $page = 1)
    {
        $query = $this->baseUserFollowing(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->select('user.*')
        ->orderBy('user.nickname', 'DESC');

        $query->skip(($page - 1) * static::LIMIT_PAGE)->take(static::LIMIT_PAGE);

        return $query->get();
    }

    /**
     * @param $user
     * @param string $search
     * @param bool $limit
     * @param bool $offset
     * @return Builder[]|Collection
     */
    public function getListUserFollowing($user, $search = '', $limit = false, $offset = false)
    {
        $query = $this->baseUserFollowing(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->select('user.*')
        ->orderBy('user.nickname', 'DESC');

        if ($limit) {
            $query->take($limit);
        }

        if ($offset) {
            $query->skip($offset);
        }

        return $query->get();
    }

    /**
     * @param User $user
     * @param string $search
     * @return int
     */
    public function countPaginatedUserFollowers($user, $search = '')
    {
        return $this->baseUserFollowers(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->count();
    }

    /**
     * @param User $user
     * @param string $search
     * @return int
     */
    public function countPaginatedUserFollowing($user, $search = '')
    {
        return $this->baseUserFollowing(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->count();
    }

    /**
     * @param $user
     * @param string $search
     * @param bool $offset
     * @return int
     */
    public function countListUserFollowing($user, $search = '', $offset = false)
    {
        $query = $this->baseUserFollowing(
            $user,
            [
                'nickname' => $search
            ]
        );

        if ($offset) {
            $query->skip($offset);
        }

        return $query->count();
    }

    public function countPaginatedConfirmationList($user, $search = '')
    {
        return $this->baseWaitConfirmation(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->count();
    }

    public function getPaginatedConfirmationList($user, $search = '', $page = 1)
    {
        $query = $this->baseWaitConfirmation(
            $user,
            [
                'nickname' => $search
            ]
        )
        ->select([
            'user.*',
            'table_follower_relation.id as follower_id'
        ])
        ->orderBy('table_follower_relation.created_at', 'DESC');

        $query->skip(($page - 1) * static::LIMIT_PAGE)->take(static::LIMIT_PAGE);

        return $query->get();
    }

}
