<?php

namespace App\PackagesApi\v4\Controllers\Capsule;

use App\Http\Controllers\Controller;
use App\Packages\Capsule\Models\Capsule;
use App\Packages\Capsule\Models\CapsuleComment;
use App\Packages\Capsule\Models\CapsuleLike;
use App\Packages\v4\Capsule\Repository\CapsuleCommentRepository;
use App\Packages\v4\Capsule\Repository\CapsuleLikeRepository;
use App\Packages\v4\Capsule\Repository\CapsuleRepository;
use App\Packages\v4\Capsule\Services\CapsuleService;
use App\Packages\v4\Capsule\Transformer\CapsuleArrayTransformer;
use App\Packages\v4\Capsule\Transformer\CapsuleCommentTransformer;
use App\Packages\User\Models\User;
use App\Packages\v4\Follower\Manager\FollowerManager;
use App\Packages\v4\User\Repository\UserRepository;
use App\Packages\v4\User\Service\UserMentionService;
use App\Packages\v4\User\Services\CapsuleAdditionalService;
use App\Packages\v4\User\Transformer\UserTransformer;
use App\PackagesApi\v4\Requests\Capsule\CommentDeleteRequest;
use App\PackagesApi\v4\Requests\Capsule\CommentRequest;
use App\PackagesApi\v4\Requests\Capsule\CommentUpdateRequest;
use App\PackagesApi\Status\StatusCode;
use App\PackagesApi\v4\Requests\Capsule\OpenRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
 * Class InfoController
 * @package App\PackagesApi\Controllers\v4\Capsule
 */
class InfoController extends Controller
{
    /** @var Capsule */
    private $capsule;

    /** @var User */
    private $user;

    /**
     * CapsuleController constructor.
     *
     * @param Request $request
     */
    public function __construct(Request $request)
    {
        $this->middleware(function (Request $request, $next) {

            $capsuleUuid = $request->get('capsule_id') ?? $request->route('capsule_id');
            $capsule = CapsuleRepository::init()->firstByUuid($capsuleUuid);

            if (!$capsule) {
                return jsonErrorEntity([
                    'message' => trans('api.msg.capsule_does_not_exists'),
                ]);
            }

            $this->capsule = $capsule;
            $this->user = user();

            return $next($request);
        });
    }

    /**
     * @param Request $request
     * @return JsonResponse
     */
    public function info(Request $request)
    {
        // if we have share key in request, try make opened user to follow capsule owner.
        if ( $request->has('share_key') && $request->filled('share_key') ) {
            if ( $this->capsule->share_key != $request->share_key )
                return jsonErrorMessage('Share key not valid');

            if ( $this->capsule->user_id != $this->user->id ) {
                $owner = UserRepository::init()->firstById($this->capsule->user_id);
                if ( $owner ) {
                    $followerManager = app(FollowerManager::class);

                    if ( $owner->is_private ) {
                        $followerManager->privateFollowUser($this->user, $owner, true);
                    } else {
                        $followerManager->followUser($this->user, $owner);
                    }
                }
            }
        }

        return jsonSuccess([
            'capsule' => CapsuleArrayTransformer::mainCapsule($this->capsule, $this->user),
        ]);
    }

    /**
     * @return JsonResponse
     */
    public function likesList()
    {
        $this->user->saveAccess('View like list');

        $capsuleLikes = CapsuleLikeRepository::init()->capsuleLikes($this->capsule);
        $capsuleLikes = $capsuleLikes->map(function (User $user) {
            return UserTransformer::smallObject($user);
        });

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

    /**
     * @param CapsuleAdditionalService $service
     * @return JsonResponse
     */
    public function subscriberList(CapsuleAdditionalService $service)
    {
        $this->user->saveAccess('View capsule subscribers list');

        return jsonSuccess([
            'users' => $service->getCapsuleSubscribedUsers($this->capsule),
        ]);
    }

    /**
     * @return JsonResponse
     */
    public function comments()
    {
        $this->user->saveAccess('View capsule comments list');

        $comments = CapsuleCommentRepository::init()->capsuleComments($this->capsule);
        $comments = $comments->map(function (CapsuleComment $comment) {
            return CapsuleCommentTransformer::commentFull($comment, $this->user);
        });

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




    // Manipulation mehtods

    /**
     * @param OpenRequest $request
     * @return JsonResponse
     */
    public function open(OpenRequest $request)
    {
        $this->user->saveAccess('Open capsule');

        if (!$this->capsule->canBeOpened()) {
            return jsonErrorEntity([
                'message' => 'Capsule can not be opened yet',
            ]);
        }

        $capsuleUpdateService = new CapsuleService($this->capsule);
        $capsuleUpdateService->openCapsule($this->user, $request);

        return jsonSuccess([
            'capsule' => CapsuleArrayTransformer::mainCapsule($this->capsule, $this->user),
        ]);
    }

    /**
     * @return JsonResponse
     *
     * @throws \Exception
     */
    public function like()
    {
        $this->user->saveAccess('Like/Unlike capsule');

        $capsuleUpdateService = new CapsuleService($this->capsule);
        $capsuleUpdateService->toggleLike($this->user);

        return jsonSuccess([
            'capsule' => CapsuleArrayTransformer::mainCapsule($this->capsule, $this->user),
        ]);
    }



    /**
     * @return JsonResponse
     *
     * @throws \Exception
     */
    public function subscribe()
    {
        $this->user->saveAccess('Subscribe/Unsubscribe capsule');

        $capsuleUpdateService = new CapsuleService($this->capsule);
        $capsuleUpdateService->toggleSubscriber($this->user);

        return jsonSuccess([
            'capsule' => CapsuleArrayTransformer::mainCapsule($this->capsule, $this->user),
        ]);
    }



    /**
     * @param CommentRequest $request
     *
     * @return JsonResponse
     */
    public function addComment(CommentRequest $request)
    {
        $this->user->saveAccess('Add comment to capsule');

        // can comment, how much comments, and so on

        $capsuleUpdateService = new CapsuleService($this->capsule);
        $comment = $capsuleUpdateService->addComment($this->user, $request->content);

        UserMentionService::processComment($comment);

        return jsonSuccess([
            'comment' => CapsuleCommentTransformer::commentFull($comment, $this->user),
        ]);
    }

    public function editComment(CommentUpdateRequest $request)
    {
        $this->user->saveAccess('Edit comment to capsule');
        /** @var CapsuleComment $comment */
        $comment = CapsuleCommentRepository::init()->firstByUuid($request->comment_id);

        /** check if user can update comment */
        if ( ! $comment ) return jsonErrorMessage('Comment not found');
        if ( $this->user->id != $comment->user_id )
            return jsonError(
                ['message' => 'User cannot edit comment'],
                StatusCode::HTTP_METHOD_NOT_ALLOWED
            );

        $capsuleUpdateService = new CapsuleService($this->capsule);
        $comment = $capsuleUpdateService->editComment($comment, $request->content);

        UserMentionService::processComment($comment);

        return jsonSuccess([
            'comment' => CapsuleCommentTransformer::commentFull($comment, $this->user),
        ]);
    }

    public function deleteComment(CommentDeleteRequest $request)
    {
        $this->user->saveAccess('Delete comment to capsule');
        /** @var CapsuleComment $comment */
        $comment = CapsuleCommentRepository::init()->firstByUuid($request->comment_id);

        /** check if user can delete comment */
        if ( ! $comment ) return jsonErrorMessage('Comment not found');
        if ( ! ($this->user->id == $comment->user_id || $this->user->id == $this->capsule->user_id) )
            return jsonError(
                ['message' => 'User cannot delete comment'],
                StatusCode::HTTP_METHOD_NOT_ALLOWED
            );

        $capsuleUpdateService = new CapsuleService($this->capsule);
        $capsuleUpdateService->deleteComment($comment);

        return jsonSuccess();
    }
}
