require 'rails_helper'

feature 'comments', type: :system, js: true do
  let(:post) { FactoryBot.create(:post) }
  let(:comment1) { FactoryBot.create(:comment, post: post) }
  let(:comment2) { FactoryBot.create(:comment, post: post) }
  let(:comment3) { FactoryBot.create(:comment, post: post, parent: comment2) }
  let(:user) { FactoryBot.create(:user) }

  let(:commentsSelector) { '.commentsContainer' }
  let(:commentListSelector) { '.commentList' }
  let(:commentSelector) { '.comment' }
  let(:commentAuthorSelector) { '.commentAuthor' }
  let(:commentReplyBtnSelector) { '.commentReplyButton' }
  let(:newCommentFormSelector) { '.newCommentForm' }
  let(:newCommentBodySelector) { '.newCommentBody' }

  def create_comments
    comment1
    comment2
    comment3
  end

  def log_in_as(user)
    user.confirm
    sign_in user
  end

  before(:each) do
    create_comments
  end

  it 'renders correctly' do
    visit post_path(post)

    expect(page).to have_selector(commentsSelector, count: 1)
  end

  it 'renders a new comment form and replies form if logged in' do
    log_in_as user
    visit post_path(post)
    comments_count = Comment.where(post_id: post.id).count

    expect(page).to have_selector(newCommentFormSelector, count: 1, visible: true)
    expect(page).to have_selector(newCommentBodySelector, count: 1, visible: true)

    # don't know why don't work
    # expect(page).to have_selector(newCommentFormSelector, count: comments_count, visible: false)
    # expect(page).to have_selector(newCommentBodySelector, count: comments_count, visible: false)
  end

  it 'does not render a new comment form if not logged in' do
    visit post_path(post)

    expect(page).to have_no_selector(newCommentBodySelector)
  end

  it 'renders all comments of a post' do
    visit post_path(post)

    within commentsSelector do
      expect(page).to have_selector(commentSelector, count: 3)
      expect(page).to have_content(/#{comment1.body}/i)
      expect(page).to have_content(/#{comment2.body}/i)
      expect(page).to have_content(/#{comment3.body}/i)
    end
  end

  it 'renders nested comments' do
    visit post_path(post)

    within commentsSelector do
      expect(page).to have_selector(
        "#{commentListSelector} > #{commentListSelector}",
        count: 1
      ) # one nested comment
    end
  end

  it 'renders the author full name for each comment' do
    visit post_path(post)

    page.all(:css, commentSelector).each do |comment|
      expect(comment).to have_selector(commentAuthorSelector)
      expect(comment).to have_content(/#{post.user.full_name}/i)
    end
  end

  it 'renders a reply button for each comment' do
    visit post_path(post)

    page.all(:css, commentSelector).each do |comment|
      expect(comment).to have_selector(commentReplyBtnSelector)
      expect(comment).to have_content(/#{'reply'}/i)
    end
  end

  it 'enables users to comment' do
    log_in_as user
    visit post_path(post)

    comments_count = Comment.where(post_id: post.id).count
    comment_body = 'this is a comment!'

    find(newCommentBodySelector).fill_in with: comment_body
    click_button 'Submit'
    visit post_path(post)

    expect(Comment.where(post_id: post.id).count).to eq(comments_count + 1)
  end

  it 'notifies post owner when comment is posted' do
    log_in_as user
    visit post_path(post)
    allow(UserMailer).to receive_message_chain(:notify_post_owner, :deliver_later)

    comment_body = 'this is a comment!'

    find(newCommentBodySelector).fill_in with: comment_body
    click_button 'Submit'
    visit post_path(post)

    expect(UserMailer).to have_received(:notify_post_owner)
  end

  it 'does not notify the post owner if he refused notifications' do
    post_owner = FactoryBot.create(:user, notifications_enabled: false)
    post = FactoryBot.create(:post, user: post_owner)
    log_in_as user
    visit post_path(post)
    allow(UserMailer).to receive_message_chain(:notify_post_owner, :deliver_later)

    comment_body = 'this is a comment!'

    find(newCommentBodySelector).fill_in with: comment_body
    click_button 'Submit'
    visit post_path(post)

    expect(UserMailer).not_to have_received(:notify_post_owner)
  end
end
