<?php

namespace App\PackagesApi\v3\Controllers\Friend;

use App\Http\Controllers\Controller;
use App\Packages\Core\Exceptions\RecordExistsException;
use App\Packages\Core\Exceptions\RecordNotExistsException;
use App\Packages\Friend\Models\FriendInvite;
use App\Packages\Friend\Models\FriendRelation;
use App\Packages\Friend\Repository\FriendInviteRepository;
use App\Packages\Friend\Repository\FriendRepository;
use App\Packages\Phone\Service\PhoneParseService;
use App\Packages\User\Manager\UserEntityManager;
use App\Packages\User\Models\User;
use App\Packages\User\Repository\UserRepository;
use App\Packages\User\Service\InviteService;
use App\Packages\User\Transformer\UserTransformer;
use App\PackagesApi\v3\Requests\Friend\AcceptDeclineInviteRequest;
use App\PackagesApi\v3\Requests\Friend\RemoveInviteRequest;
use App\PackagesApi\v3\Requests\Friend\SendInviteRequest;
use App\PackagesApi\v3\Requests\Friend\UserPhoneHashRequest;
use App\PackagesApi\v3\Requests\Friend\UserPhoneRequest;
use Illuminate\Http\JsonResponse;
use libphonenumber\PhoneNumber;

/**
 * Class InviteController
 * @package App\PackagesApi\Controllers\v2\Friend
 */
class InviteController extends Controller
{
    /** @var User */
    private $user;

    /** @var InviteService */
    private $inviteService;

    public function __construct(InviteService $inviteService)
    {
        $this->user = user();
        $this->inviteService = $inviteService;
    }

    /**
     * @TODO: Remove unused methods
     *
     * @param UserPhoneHashRequest $request
     *
     * @return JsonResponse
     */
    public function inviteByHash(UserPhoneHashRequest $request)
    {
        $phoneHash = $request->phone_hash;
        $user = UserRepository::init()->firstByPhoneHash($phoneHash);
        if (!$user) {
            $user = UserEntityManager::createUserFromPhoneHash($phoneHash);
        }

        try {
            $this->inviteService->send($this->user, $user);
        } catch (RecordExistsException $e) {
            return jsonErrorEntity([
                'message' => $e->getMessage(),
            ]);
        }

        $responseUser = UserTransformer::smallObject($user);

        return jsonSuccess([
            'user' => $responseUser
        ]);
    }

    /**
     * @TODO: Refactore, can be changed to Only Send invite -> with only 1 requst
     *
     * @param UserPhoneRequest $request
     *
     * @return JsonResponse
     */
    public function userByPhone(UserPhoneRequest $request)
    {
        /** @var PhoneParseService $phoneService */
        $phoneService = app()->make(PhoneParseService::class);

        $users = [];
        foreach ($request->phone_full as $number) {
            $swissNumberProto = $phoneService->parseNumber($number, user()->phone_code);
            if (!$swissNumberProto instanceof PhoneNumber) {
                continue;
            }

            if (!$phoneService->isValidNumber($swissNumberProto)) {
                continue;
            }

            $user = UserEntityManager::createUserFromPhoneNumber(
                $swissNumberProto->getCountryCode(),
                $swissNumberProto->getNationalNumber()
            );

            $users[] = UserTransformer::smallObject($user);
        }

        return jsonSuccess([
            'users' => $users
        ]);
    }

    /**
     * @return JsonResponse
     */
    public function invites()
    {
        $this->user->saveAccess('View invites list');
        $invites = $this->inviteService->getInvites($this->user);

        return jsonSuccess([
            'invites' => $invites,
        ]);
    }

    /**
     * @return JsonResponse
     */
    public function sentInvites()
    {
        $this->user->saveAccess('View invites list');
        $invites = $this->inviteService->getSentInvites($this->user);

        return jsonSuccess([
            'invites' => $invites,
        ]);
    }

    /**
     * @param SendInviteRequest $request
     *
     * @return JsonResponse
     */
    public function sendInvite(SendInviteRequest $request)
    {
        $this->user->saveAccess('Send invite request');

        $user = UserRepository::init()->firstByUuid($request->user_id);
        if (!$user) {
            return jsonErrorEntity([
                'message' => 'User does not exists',
            ]);
        }

        $relation = FriendRepository::init()->existsFriend(user(), $user);
        if ($relation) {
            return jsonErrorEntity([
                'message' => 'This user is already your friend',
            ]);
        }

        if ($this->user->id == $user->id) {
            return jsonErrorEntity([
                'message' => 'Same user',
            ]);
        }

        try {
            $this->inviteService->send($this->user, $user);

        } catch (RecordExistsException $e) {
            return jsonErrorEntity([
                'message' => $e->getMessage(),
            ]);
        }

        return jsonSuccess([
            'message' => 'Invite has been sent',
        ]);
    }

    /**
     * @param RemoveInviteRequest $request
     *
     * @return JsonResponse
     */
    public function removeInvite(RemoveInviteRequest $request)
    {
        $this->user->saveAccess('Remove invite request');

        $user = UserRepository::init()->firstByUuid($request->user_id);
        if ( ! $user ) {
            return jsonErrorEntity([
                'message' => 'User does not exists',
            ]);
        }

        $relation = FriendRepository::init()->existsFriend(user(), $user);
        if ( $relation ) {
            return jsonErrorEntity([
                'message' => 'This user is already your friend',
            ]);
        }

        if ( $this->user->id == $user->id ) {
            return jsonErrorEntity([
                'message' => 'Same user',
            ]);
        }

        try {
            $this->inviteService->remove($this->user, $user);

        } catch (RecordExistsException $e) {
            return jsonErrorEntity([
                'message' => $e->getMessage(),
            ]);
        }

        return jsonSuccess([
            'message' => 'Invite has been removed',
        ]);
    }

    /**
     * @param AcceptDeclineInviteRequest $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function acceptInvite(AcceptDeclineInviteRequest $request)
    {
        try {
            $invite = FriendInviteRepository::init()->findInvite($request->invite_id);

            $this->inviteService->acceptInvite($invite);
            $this->user->saveAccess('Accept invite request');

        } catch (RecordNotExistsException $exception) {
            return jsonErrorEntity([
                'message' => $exception->getMessage(),
            ]);
        }

        return jsonSuccess([
            'message' => 'Friend has been added',
        ]);
    }

    /**
     * @param AcceptDeclineInviteRequest $request
     *
     * @return JsonResponse
     */
    public function declineInvite(AcceptDeclineInviteRequest $request)
    {
        try {
            $this->inviteService->decline($request->invite_id);
            $this->user->saveAccess('Decline invite request');

        } catch (RecordNotExistsException $exception) {
            return jsonErrorEntity([
                'message' => $exception->getMessage(),
            ]);
        }

        return jsonSuccess([
            'message' => 'Invitation has been declined',
        ]);
    }
}
