<?php

namespace App\Packages\User\Service;

use App\Packages\Core\Exceptions\RecordExistsException;
use App\Packages\Core\Exceptions\RecordNotExistsException;
use App\Packages\Friend\Models\FriendInvite;
use App\Packages\Friend\Repository\FriendInviteRepository;
use App\Packages\Friend\Transformer\InviteTransformer;
use App\Packages\User\Models\User;
use App\Packages\User\Models\UserNotificationPush;
use App\Packages\User\Notifications\NotificationInviteAccept;
use App\Packages\User\Notifications\NotificationInviteNew;
use App\Packages\User\Notifications\TypesNotification;
use App\Packages\User\Repository\UserNotificationPushRepository;
use App\Packages\User\Services\FriendService;
use Illuminate\Support\Collection;

/**
 * Class InviteService
 * @package App\Packages\User\Transformer
 */
class InviteService
{
    /**
     * @var FriendService
     */
    private $friendService;

    public function __construct(FriendService $friendService)
    {
        $this->friendService = $friendService;
    }

    /**
     * @param User $user
     * @return FriendInvite[]|Collection
     */
    public function getInvites(User $user)
    {
        $invites = FriendInviteRepository::init()->getInvites($user);
        $invites = $invites->map(function ($invite) {
            return InviteTransformer::transformObject($invite);
        });

        return $invites;
    }

    /**
     * @param User $user
     * @return FriendInvite[]|Collection
     */
    public function getSentInvites(User $user)
    {
        $invites = FriendInviteRepository::init()->getSentInvites($user);
        $invites = $invites->map(function ($invite) {
            return InviteTransformer::transformSentObject($invite);
        });

        return $invites;
    }

    /**
     * @param User $user
     * @param User $friend
     *
     * @return bool
     */
	public function send(User $user, User $friend)
	{
	    /** If user already has invite from friend */
        if ($invite = FriendInviteRepository::init()->getCreatedInvite($friend, $user)) {
            $this->acceptInvite($invite);

            return true;
        }

		$created = FriendInviteRepository::init()->checkCreatedInvite($user, $friend);
		if ($created) {
			throw new RecordExistsException('Friend request already exists');
		}

		if ($user->phone_hash == $friend->phone_hash) {
            throw new RecordExistsException('Can not send invite to yourself');
        }

		FriendInvite::createInvite($user, $friend);

        /** Send notification */
        NotificationInviteNew::dispatch($friend, $user)
            ->onQueue(TypesNotification::QUEUE_NOTIFICATIONS);

        return true;
	}

    /**
     * @param User $user
     * @param User $friend
     *
     * @return bool
     */
	public function remove(User $user, User $friend)
    {
        $invite = FriendInviteRepository::init()->getCreatedInvite($user, $friend);

        if ( ! $invite ) throw new RecordExistsException('Friend request not found');

        $invite->delete();

        if ( $push_notification = UserNotificationPushRepository::init()->findFriendInvite($friend, $user) ) {
            $push_notification->delete();
        }

        return true;
    }

    /**
     * @param FriendInvite $invite
     */
	public function acceptInvite(FriendInvite $invite)
    {
        $this->friendService->createFriendFromInvite($invite);
        FriendInviteRepository::init()->deleteAllRelativeInvites($invite->user, $invite->friend);

        /** Send notification */
        NotificationInviteAccept::dispatch($invite->user, $invite->friend)
            ->onQueue(TypesNotification::QUEUE_NOTIFICATIONS);
    }

	/**
	 * @param $inviteId
	 *
	 * @throws RecordNotExistsException
	 */
	public function decline($inviteId)
	{
		$invite = FriendInviteRepository::init()->findInvite($inviteId);
		if (!$invite) {
			throw new RecordNotExistsException('Invite does not exists');
		}

        $invite->delete();
	}
}