<?php

namespace App\Packages\v4\Capsule\Services;

use App\Packages\Capsule\Models\Capsule;
use App\Packages\Capsule\Models\CapsuleTaggedUser;
use App\Packages\Capsule\Models\CapsuleTeaser;
use App\Packages\Capsule\Models\CapsuleVideo;
use App\Packages\v4\Capsule\Repository\CapsuleTaggedUserRepository;
use App\Packages\v4\Core\Exceptions\RecordExistsException;
use App\Packages\Core\Models\Address;
use App\Packages\Friend\Models\FriendInvite;
use App\Packages\Friend\Models\FriendRelation;
use App\Packages\v4\Friend\Repository\FriendInviteRepository;
use App\Packages\v4\Friend\Repository\FriendRepository;
use App\Packages\v4\User\Manager\UserEntityManager;
use App\Packages\User\Models\User;
use App\Packages\v4\User\Notifications\NotificationTagged;
use App\Packages\v4\User\Notifications\NotificationUploadComplete;
use App\Packages\v4\User\Notifications\TypesNotification;
use App\Packages\v4\User\Repository\UserRepository;
use App\Packages\v4\User\Service\InviteService;
use App\PackagesApi\v4\Requests\Capsule\CompleteRequest;
use App\PackagesApi\v4\Requests\Capsule\TagUsersRequest;
use App\PackagesApi\v4\Requests\Capsule\UpdateRequest;

/**
 * Class CapsuleCreateService
 * @package App\Packages\Capsule\Services
 */
class CapsuleFactoryService
{
    /**
     * @param User $user
     *
     * @return Capsule
     */
    public function startCreate(User $user)
    {
        return Capsule::createBlankCapsule($user);
    }

    /**
     * @param $fileName
     *
     * @return CapsuleVideo
     */
    public function createVideoRow($fileName)
    {
        $videoData = CapsuleVideo::createFileData();
        $videoData->aws_bucket = env('AWS_VIDEO_BUCKET');
        $videoData->aws_key = $fileName;
        $videoData->save();

        return $videoData;
    }

    /**
     * @param $fileName
     *
     * @return CapsuleTeaser
     */
    public function createTeaserRow($fileName)
    {
        $teaserData = CapsuleTeaser::createFileData();
        $teaserData->aws_bucket = env('AWS_TEASER_BUCKET');
        $teaserData->aws_key = $fileName;
        $teaserData->save();

        return $teaserData;
    }

    /**
     * @param Capsule $capsule
     * @param CompleteRequest $completeRequest
     *
     * @return Capsule
     */
    public function createCapsuleRow(Capsule $capsule, CompleteRequest $completeRequest)
    {
        $capsule->caption = $completeRequest->caption;
        $capsule->is_private = $completeRequest->is_private;
        $capsule->open_at = $completeRequest->opens_at;
        $capsule->is_complete = true;
        $capsule->status = $capsule->determineCapsuleStatus();
        $capsule->save();

        return $capsule;
    }

    public function createCapsuleRowForDemo(Capsule $capsule, $data)
    {
        if (isset($data['caption'])) $capsule->caption = $data['caption'];
        if (isset($data['is_private'])) $capsule->is_private = $data['is_private'];
        if (isset($data['open_at'])) $capsule->open_at = $data['open_at'];
        $capsule->is_complete = true;
        $capsule->status = $capsule->determineCapsuleStatus();
        $capsule->save();

        return $capsule;
    }

    public function updateCapsuleRow(Capsule $capsule, UpdateRequest $updateRequest)
    {
        $capsule->caption = $updateRequest->caption;
        $capsule->is_private = $updateRequest->is_private;
        $capsule->save();

        return $capsule;
    }

    /**
     * @param Capsule $capsule
     * @param CapsuleVideo $capsuleVideo
     *
     * @return Capsule
     */
    public function bindVideoToCapsule(Capsule $capsule, CapsuleVideo $capsuleVideo)
    {
        $capsule->video_id = $capsuleVideo->id;
        $capsule->save();

        return $capsule;
    }

    /**
     * @param Capsule $capsule
     * @param CapsuleTeaser $capsuleTeaser
     *
     * @return Capsule
     */
    public function bindTeaserToCapsule(Capsule $capsule, CapsuleTeaser $capsuleTeaser)
    {
        $capsule->teaser_id = $capsuleTeaser->id;
        $capsule->save();

        return $capsule;
    }

    /**
     * @param Capsule $capsule
     * @param string $placeId
     *
     * @return Capsule
     */
    public function bindAddressToCapsule(Capsule $capsule, string $placeId)
    {
        $address = Address::createFullAddressFromPlace($capsule->user, $placeId);

        $capsule->address_id = $address->id;
        $capsule->save();

        return $capsule;
    }

    /**
     * @param Capsule $capsule
     * @param CompleteRequest $completeRequest
     *
     * @return Capsule
     *
     * @throws \App\Packages\Core\Exceptions\RecordExistsException
     */
    public function completeCreate(Capsule $capsule, CompleteRequest $completeRequest)
    {
        $capsule = $this->createCapsuleRow($capsule, $completeRequest);

        $videoData = $this->createVideoRow($completeRequest->video_name);
        $capsule = $this->bindVideoToCapsule($capsule, $videoData);

        if ($completeRequest->filled('teaser_name')) {
            $teaserData = $this->createTeaserRow($completeRequest->teaser_name);
            $capsule = $this->bindTeaserToCapsule($capsule, $teaserData);
        }

        /** @TOOD: After remove location place */
        if ($completeRequest->location_id) {
            $capsule = $this->bindAddressToCapsule($capsule, $completeRequest->location_id);
        }

//        if ($completeRequest->location_place) {
//            $capsule = $this->bindAddressToCapsule($capsule, $completeRequest->location_place);
//        }

        if ($completeRequest->tagged_users) {
            $this->bindTaggedUsersToCapsules($capsule, $completeRequest->tagged_users);
        }

        /** Send notification on capsule upload */
        NotificationUploadComplete::dispatch($capsule, $capsule->user)
            ->onQueue(TypesNotification::QUEUE_NOTIFICATIONS);

        return $capsule;
    }

    public function completeCreateForDemo(Capsule $capsule, $data)
    {
        $capsule = $this->createCapsuleRowForDemo($capsule, $data);

        $videoData = $this->createVideoRow($data['file_name']);
        $capsule = $this->bindVideoToCapsule($capsule, $videoData);

        if (isset($data['location_id'])) {
            $capsule = $this->bindAddressToCapsule($capsule, $data['location_id']);
        }

        if (isset($data['tagged_users'])) {
            $this->bindTaggedUsersToCapsules($capsule, $data['tagged_users']);
        }

        return $capsule;
    }

    /**
     * @param Capsule $capsule
     * @param array $taggedUsers
     */
    public function bindTaggedUsersToCapsules(Capsule $capsule, array $taggedUsers)
    {
        foreach ($taggedUsers as $userUuid) {

            /** Can't tag user owner */
            if ($capsule->user->uuid == $userUuid) {
                continue;
            }

            /** Get user row. If not exist continue this loop */
            if ( ! $taggedUser = UserRepository::init()->firstByUuid($userUuid) ) {
                continue;
            }

            /** Don't take not registered users. */
            if ( ! $taggedUser->is_registered ) continue;

            /** If user is already tagged in capsule */
            if (CapsuleTaggedUserRepository::init()->existsTaggedUser($capsule, $taggedUser)) {
                continue;
            }

            /** Assign user to capsule and send notification */
            CapsuleTaggedUser::assignTaggedUser($capsule, $capsule->user, $taggedUser);

            /** Notify user about tagged in capsule */
            NotificationTagged::dispatch($capsule, $taggedUser, $capsule->user)
                ->onQueue(TypesNotification::QUEUE_NOTIFICATIONS);
        }

        $capsule->refreshTaggedUserCount();
    }

    /**
     * @param Capsule $capsule
     * @param TagUsersRequest $tagUsersRequest
     *
     * @return Capsule
     */
    public function tagUsers(Capsule $capsule, TagUsersRequest $tagUsersRequest)
    {
        $taggedUsers = [];
        if ($tagUsersRequest->tagged_users) {
            $taggedUsers = $tagUsersRequest->tagged_users;
        }

        CapsuleTaggedUserRepository::init()
            ->clearAllExceptTaggedUsersByUuid($capsule, $taggedUsers);

        $this->bindTaggedUsersToCapsules($capsule, $taggedUsers);

        return $capsule;
    }

    /**
     * @param Capsule $capsule
     * @param UpdateRequest $updateRequest
     * @return Capsule
     */
    public function update(Capsule $capsule, UpdateRequest $updateRequest)
    {
        $capsule = $this->updateCapsuleRow($capsule, $updateRequest);

        /** @TOOD: After remove location place */
        if ($updateRequest->location_id) {
            $capsule = $this->bindAddressToCapsule($capsule, $updateRequest->location_id);
        }

        if ($updateRequest->tagged_users) {
            $taggedUsers = [];
            if ($updateRequest->tagged_users) {
                $taggedUsers = $updateRequest->tagged_users;
            }

            CapsuleTaggedUserRepository::init()
                ->clearAllExceptTaggedUsersByUuid($capsule, $taggedUsers);

            $this->bindTaggedUsersToCapsules($capsule, $taggedUsers);
        } else {
            CapsuleTaggedUserRepository::init()
                ->clearAllTaggedUsers($capsule);
        }

        return $capsule;
    }
}
