# frozen_string_literal: true

require 'simplecov'
SimpleCov.start

require 'rails_helper'

RSpec.describe BooksController, type: :controller do
  describe 'routing' do
    context 'have' do
      it do
        expect(get: '/books').to route_to(
          'books#index'
        )
      end

      it do
        expect(delete: '/books/1').to route_to(
          controller: 'books',
          action: 'destroy',
          id: '1'
        )
      end

      it do
        expect(get: '/books/new').to route_to(
          controller: 'books',
          action: 'new'
        )
      end

      it do
        expect(post: '/books').to route_to(
          controller: 'books',
          action: 'create'
        )
      end

      it do
        expect(get: '/books/1').to route_to(
          controller: 'books',
          action: 'show',
          id: '1'
        )
      end

      it do
        expect(patch: '/books/1').to route_to(
          controller: 'books',
          action: 'update',
          id: '1'
        )
      end

      it do
        expect(put: '/books/1').to route_to(
          controller: 'books',
          action: 'update',
          id: '1'
        )
      end

      it do
        expect(get: '/books/1/edit').to route_to(
          controller: 'books',
          action: 'edit',
          id: '1'
        )
      end
    end
  end
end

describe BooksController, type: :controller do
  context 'GET #index' do
    let(:book) { create(:book) }

    it 'should success and render to index page' do
      get 'index'
      expect(response).to have_http_status(200)
      expect(response).to render_template :index
    end

    it 'assigns the category' do
      get :index
      expect(assigns(:books)).to include(book)
    end
  end

  context 'GET #edit' do
    let(:book) { create(:book) }

    it 'should success and render to index page' do
      get :edit, params: { id: book.id.to_s }
      expect(response).to have_http_status(200)
      expect(response).to render_template :edit
    end

    it 'assigns the category' do
      get :edit, params: { id: book.id.to_s }
      expect(assigns(:book)).to eq(book)
    end
  end

  context 'path #update' do
    let(:book) { create(:book) }

    it 'should success and render to index page' do
      patch :update, params: {
        id: book.id.to_s,
        book: {
          author: book.author,
          name: book.name
        }
      }
      expect(response).to have_http_status(302)
    end

    it 'should success and render to index page' do
      patch :update, params: {
        id: book.id.to_s,
        book: {
          author: book.author,
          name: book.name
        }
      }
      expect(response).to have_http_status(302)
    end

    it 'should contain book' do
      patch :update, params: {
        id: book.id.to_s,
        book: {
          author: book.author,
          name: book.name
        }
      }
      expect(@controller.instance_variable_get(:@book).class).to eq(Book)
    end
  end

  context 'PUT #update' do
    let(:book) { create(:book) }

    it 'should success and render to index page' do
      put :update, params: {
        id: book.id.to_s,
        book: {
          author: book.author,
          name: book.name
        }
      }
      expect(response).to have_http_status(302)
    end

    it 'assigns the category' do
      put :update, params: {
        id: book.id.to_s,
        book: {
          author: book.author,
          name: book.name
        }
      }
      expect(assigns(:book)).to eq(book)
    end
  end

  context 'GET #show' do
    let(:book) { create(:book) }

    it 'should success and render to index page' do
      get :show, params: { id: book.id }
      expect(response).to have_http_status(200)
      expect(response).to render_template :show
    end

    it 'assigns the book' do
      get :show, params: { id: book.id }
      expect(assigns(:book)).to eq(book)
    end
  end

  context 'GET #show when book no exist' do
    it 'get show redirect to index when book no exist' do
      get :show, params: { id: 'noexist123id' }
      expect(response).to have_http_status(302)
      assert_response :redirect
    end
  end

  context 'GET #show' do
    let(:book) { create(:book) }

    it 'should success and render to index page' do
      get :show, params: { id: book.id }
      expect(response).to have_http_status(200)
      expect(response).to render_template :show
    end

    it 'assigns the book' do
      get :show, params: { id: book.id }
      expect(assigns(:book)).to eq(book)
    end

    context 'instance variables' do
      it 'contain book' do
        get :show, params: { id: book.id }
        expect(@controller.instance_variable_get(:@book).class).to eq(Book)
      end

      it 'contain histories' do
        get :show, params: { id: book.id }
        expect(@controller.instance_variable_get(:@histories).class).to eq(Mongoid::Criteria)
      end

      it 'contain comments' do
        get :show, params: { id: book.id }
        expect(@controller.instance_variable_get(:@comments).class).to eq(Mongoid::Criteria)
      end

      it 'contain activity' do
        get :show, params: { id: book.id }
        expect(@controller.instance_variable_get(:@activity).class).to eq(NilClass)
      end

      it 'contain taked_book' do
        get :show, params: { id: book.id }
        expect(@controller.instance_variable_get(:@taked_book).class).to eq(NilClass)
      end
    end
  end

  context 'GET #new' do
    it 'should success and render to index page' do
      get :new
      expect(response).to have_http_status(200)
      expect(response).to render_template :new
    end

    it 'contain book' do
      get :new
      expect(@controller.instance_variable_get(:@book).class).to eq(Book)
    end
  end

  context 'DELETE #destroy' do
    let!(:book) { create :book }

    it 'should delete book' do
      expect { delete :destroy, params: { id: book.id } }.to change(Book, :count).by(-1)
    end
  end

  context 'book #create' do
    it 'should create new book' do
      expect do
        post :create, params: { book: { name: 'name', author: 'Author' } }
      end.to change(Book, :count).by(1)
    end

    it 'should render template#new if no name' do
      post :create, params: { book: { author: 'Author' } }
      assert_template :new
    end

    it 'should render template#new if no author' do
      post :create, params: { book: { name: 'Name' } }
      assert_template :new
    end
  end

  context 'actions' do
    %i[top_books].each do |action|
      it { should use_before_action(action) }
    end
  end

  context 'Book index variables' do
    it 'should contein empty list books' do
      get :index
      expect(@controller.instance_variable_get(:@books).count).to eq(0)
    end

    it 'should contein empty top book' do
      get :index
      expect(@controller.instance_variable_get(:@top_books).count).to eq(0)
    end

    it 'list book -- Array' do
      get :index
      expect(@controller.instance_variable_get(:@top_books).class).to eq(Array)
    end

    it 'shoul contain all books' do
      10.times do
        create(:book)
      end
      get :index
      expect(@controller.instance_variable_get(:@books).count).to eq(10)
    end

    it 'shoul contain top 5 boock' do
      10.times do
        create(:book)
      end
      get :index
      expect(@controller.instance_variable_get(:@top_books).count).to eq(5)
    end

    it 'contain empty instance variable taked books' do
      get :index
      expect(@controller.instance_variable_get(:@taked_book).count).to eq(0)
    end

    it 'taked_books is Hash' do
      get :index
      expect(@controller.instance_variable_get(:@taked_book).class).to eq(Hash)
    end
  end

  context 'Book show variables' do
    let(:book) { create(:book) }

    it 'rendered book eq to book' do
      get :show, params: { id: book.id }
      expect(@controller.instance_variable_get(:@book)).to eq(book)
    end

    it 'contain histories' do
      get :show, params: { id: book.id }
      expect(@controller.instance_variable_get(:@histories).count).to eq(0)
    end

    it 'contain comments' do
      get :show, params: { id: book.id }
      expect(@controller.instance_variable_get(:@comments).count).to eq(0)
    end

    it 'contain rate_count' do
      get :show, params: { id: book.id }
      expect(@controller.instance_variable_get(:@rate_count)).to eq(0)
    end
  end
end
