require 'test_helper'
require 'active_record'

Mongo.setup!

module Elasticsearch
  module Model
    class MultipleModelsIntegration < Elasticsearch::Test::IntegrationTestCase
      context "Multiple models" do
        setup do
          ActiveRecord::Schema.define(:version => 1) do
            create_table :episodes do |t|
              t.string :name
              t.datetime :created_at, :default => 'NOW()'
            end

            create_table :series do |t|
              t.string :name
              t.datetime :created_at, :default => 'NOW()'
            end
          end

          module ::NameSearch
            extend ActiveSupport::Concern

            included do
              include Elasticsearch::Model
              include Elasticsearch::Model::Callbacks

              settings index: {number_of_shards: 1, number_of_replicas: 0} do
                mapping do
                  indexes :name, type: 'string', analyzer: 'snowball'
                  indexes :created_at, type: 'date'
                end
              end
            end
          end

          class ::Episode < ActiveRecord::Base
            include NameSearch
          end

          class ::Series < ActiveRecord::Base
            include NameSearch
          end

          [::Episode, ::Series].each do |model|
            model.delete_all
            model.__elasticsearch__.create_index! force: true
            model.create name: "The #{model.name}"
            model.create name: "A great #{model.name}"
            model.create name: "The greatest #{model.name}"
            model.__elasticsearch__.refresh_index!
          end

        end

        should "find matching documents across multiple models" do
          response = Elasticsearch::Model.search(%q<"The greatest Episode"^2 OR "The greatest Series">, [Series, Episode])

          assert response.any?, "Response should not be empty: #{response.to_a.inspect}"

          assert_equal 2, response.results.size
          assert_equal 2, response.records.size

          assert_instance_of Elasticsearch::Model::Response::Result, response.results.first
          assert_instance_of Episode, response.records.first
          assert_instance_of Series, response.records.last

          assert_equal 'The greatest Episode', response.results[0].name
          assert_equal 'The greatest Episode', response.records[0].name

          assert_equal 'The greatest Series', response.results[1].name
          assert_equal 'The greatest Series', response.records[1].name
        end

        should "provide access to results" do
          response = Elasticsearch::Model.search(%q<"A great Episode"^2 OR "A great Series">, [Series, Episode])

          assert_equal 'A great Episode', response.results[0].name
          assert_equal true,              response.results[0].name?
          assert_equal false,             response.results[0].boo?

          assert_equal 'A great Series', response.results[1].name
          assert_equal true,             response.results[1].name?
          assert_equal false,            response.results[1].boo?
        end

        should "only retrieve records for existing results" do
          ::Series.find_by_name("The greatest Series").delete
          ::Series.__elasticsearch__.refresh_index!
          response = Elasticsearch::Model.search(%q<"The greatest Episode"^2 OR "The greatest Series">, [Series, Episode])

          assert response.any?, "Response should not be empty: #{response.to_a.inspect}"

          assert_equal 2, response.results.size
          assert_equal 1, response.records.size

          assert_instance_of Elasticsearch::Model::Response::Result, response.results.first
          assert_instance_of Episode, response.records.first

          assert_equal 'The greatest Episode', response.results[0].name
          assert_equal 'The greatest Episode', response.records[0].name
        end

        should "paginate the results" do
          response = Elasticsearch::Model.search('series OR episode', [Series, Episode])

          assert_equal 3, response.page(1).per(3).results.size
          assert_equal 3, response.page(2).per(3).results.size
          assert_equal 0, response.page(3).per(3).results.size
        end

        if Mongo.available?
          Mongo.connect_to 'mongoid_collections'

          context "Across mongoid models" do
            setup do
              class ::Image
                include Mongoid::Document
                include Elasticsearch::Model
                include Elasticsearch::Model::Callbacks

                field :name, type: String
                attr_accessible :name if respond_to? :attr_accessible

                settings index: {number_of_shards: 1, number_of_replicas: 0} do
                  mapping do
                    indexes :name, type: 'string', analyzer: 'snowball'
                    indexes :created_at, type: 'date'
                  end
                end

                def as_indexed_json(options={})
                  as_json(except: [:_id])
                end
              end

              Image.delete_all
              Image.__elasticsearch__.create_index! force: true
              Image.create! name: "The Image"
              Image.create! name: "A great Image"
              Image.create! name: "The greatest Image"
              Image.__elasticsearch__.refresh_index!
              Image.__elasticsearch__.client.cluster.health wait_for_status: 'yellow'
            end

            should "find matching documents across multiple models" do
              response = Elasticsearch::Model.search(%q<"greatest Episode" OR "greatest Image"^2>, [Episode, Image])

              assert response.any?, "Response should not be empty: #{response.to_a.inspect}"

              assert_equal 2, response.results.size
              assert_equal 2, response.records.size

              assert_instance_of Elasticsearch::Model::Response::Result, response.results.first
              assert_instance_of Image, response.records.first
              assert_instance_of Episode, response.records.last

              assert_equal 'The greatest Image', response.results[0].name
              assert_equal 'The greatest Image', response.records[0].name

              assert_equal 'The greatest Episode', response.results[1].name
              assert_equal 'The greatest Episode', response.records[1].name
            end
          end
        end

      end
    end
  end
end