<?php

namespace App\Http\Controllers\Gallery;

use App\Album;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Helpers\DbHelper;
use App\Helpers\PermissionsHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\StorePhotoCommentRequest;
use App\Mail\ModeratePhotoComment;
use App\Permission;
use App\Photo;
use App\PhotoComment;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException;

class PhotoCommentController extends Controller
{
    public function moderate(Request $request, $albumUrlAlias, $photoFilename, $commentID)
    {
        $album = null;

        /** @var Photo $photo */
        $photo = null;

        /** @var PhotoComment $comment */
        $comment = null;

        if (!$this->loadAlbumPhotoComment($albumUrlAlias, $photoFilename, $commentID, $album, $photo, $comment))
        {
            return null;
        }

        if (Gate::denies('moderate-comments', $photo))
        {
            App::abort(403);
            return null;
        }

        if (!$comment->isModerated())
        {
            if ($request->has('approve'))
            {
                $comment->approved_at = new \DateTime();
                $comment->approved_user_id = $this->getUser()->id;
                $comment->save();

                $request->getSession()->flash('success', trans('gallery.photo_comment_approved_successfully'));
            }
            else if ($request->has('reject'))
            {
                $comment->rejected_at = new \DateTime();
                $comment->rejected_user_id = $this->getUser()->id;
                $comment->save();

                $request->getSession()->flash('success', trans('gallery.photo_comment_rejected_successfully'));
            }
        }

        return redirect($photo->url());
    }

    public function reply(Request $request, $albumUrlAlias, $photoFilename, $commentID)
    {
        $album = null;

        /** @var Photo $photo */
        $photo = null;

        /** @var PhotoComment $comment */
        $comment = null;

        if (!$this->loadAlbumPhotoComment($albumUrlAlias, $photoFilename, $commentID, $album, $photo, $comment))
        {
            return null;
        }

        if (!User::currentOrAnonymous()->can('post-comment', $photo))
        {
            App::abort(403);
            return null;
        }

        return Theme::render('partials.photo_comments_reply_form', [
            'photo' => $photo,
            'reply_comment' => $comment
        ]);
    }

    public function store(Request $request, $albumUrlAlias, $photoFilename)
    {
        $album = null;

        /** @var Photo $photo */
        $photo = null;

        /** @var PhotoComment $comment */
        $comment = null;

        if (!$this->loadAlbumPhotoComment($albumUrlAlias, $photoFilename, 0, $album, $photo, $comment))
        {
            return null;
        }

        if (!User::currentOrAnonymous()->can('post-comment', $photo))
        {
            App::abort(403);
            return null;
        }

        // Validate and link the parent comment, if provided
        // We do this here so if the validation fails, we still have the parent comment available in the catch block
        $parentComment = null;
        if ($request->has('parent_comment_id'))
        {
            $parentComment = $photo->comments()->where('id', intval($request->get('parent_comment_id')))->first();

            if (is_null($parentComment))
            {
                //TODO $request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
                return redirect($photo->url());
            }
        }

        try
        {
            $this->validate($request, [
                'name' => 'required|max:255',
                'email' => 'sometimes|max:255|email',
                'comment' => 'required'
            ]);

            $comment = new PhotoComment();
            $comment->photo_id = $photo->id;
            $comment->fill($request->only(['name', 'email', 'comment']));

            if (!is_null($parentComment))
            {
                $comment->parent_comment_id = $parentComment->id;
            }

            // Set the created user ID if we're logged in
            $user = $this->getUser();
            if (!is_null($user) && !$user->isAnonymous())
            {
                $comment->created_user_id = $user->id;
            }

            // Auto-approve the comment if we're allowed to moderate comments
            $isAutoApproved = false;
            if (Gate::allows('moderate-comments', $photo))
            {
                $comment->approved_at = new \DateTime();
                $comment->approved_user_id = $user->id;
                $isAutoApproved = true;
            }

            // Auto-approve the comment if settings allow
            if ($user->isAnonymous() && !UserConfig::get('moderate_anonymous_users'))
            {
                $comment->approved_at = new \DateTime();
                $comment->approved_user_id = null; // we don't have a user ID to set!
                $isAutoApproved = true;
            }
            else if (!$user->isAnonymous() && !UserConfig::get('moderate_known_users'))
            {
                $comment->approved_at = new \DateTime();
                $comment->approved_user_id = $user->id;
                $isAutoApproved = true;
            }

            // Send notification e-mails to moderators or album owner
            if (!$isAutoApproved)
            {
                $this->notifyAlbumModerators($album, $photo, $comment);
            }

            $comment->save();

            if ($isAutoApproved)
            {
                $request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully'));
            }
            else
            {
                $request->getSession()->flash('success', trans('gallery.photo_comment_posted_successfully_pending_moderation'));
            }

            if ($request->isXmlHttpRequest())
            {
                return response()->json(['redirect_url' => $photo->url()]);
            } else
            {
                return redirect($photo->url());
            }
        }
        catch (ValidationException $e)
        {
            if (!is_null($parentComment))
            {
                return redirect()
                    ->to($photo->replyToCommentFormUrl($parentComment->id))
                    ->withErrors($e->errors())
                    ->withInput($request->all());
            }
            else
            {
                return redirect()
                    ->back()
                    ->withErrors($e->errors())
                    ->withInput($request->all());
            }
        }
    }

    private function loadAlbumPhotoComment($albumUrlAlias, $photoFilename, $commentID, &$album, &$photo, &$comment)
    {
        $album = DbHelper::getAlbumByPath($albumUrlAlias);
        if (is_null($album))
        {
            App::abort(404);
            return false;
        }

        $this->authorizeForUser($this->getUser(), 'view', $album);

        $photo = PhotoController::loadPhotoByAlbumAndFilename($album, $photoFilename);

        if (!UserConfig::get('allow_photo_comments'))
        {
            // Not allowed to post comments
            App::abort(404);
            return false;
        }

        if (intval($commentID > 0))
        {
            $comment = $photo->comments()->where('id', $commentID)->first();
            if (is_null($comment))
            {
                App::abort(404);
                return false;
            }
        }

        return true;
    }

    /**
     * Sends an e-mail notification to an album's moderators that a comment is available to moderate.
     * @param Album $album
     * @param Photo $photo
     * @param PhotoComment $comment
     */
    private function notifyAlbumModerators(Album $album, Photo $photo, PhotoComment $comment)
    {
        // Get all users from the cache
        $helper = new PermissionsHelper();
        $moderators = $helper->usersWhoCan_Album($album, 'moderate-comments');

        /** @var User $moderator */
        foreach ($moderators as $moderator)
        {
            Mail::to($moderator)->send(new ModeratePhotoComment($moderator, $album, $photo, $comment));
        }

        dd($moderators);
    }
}