module Rooms
  class TitleGenerator
    attr_reader :room, :locale

    def initialize(room, locale="en")
      @room = room
      @locale = locale
    end

    def generate
      if room_type_number_and_destination.present? && size_adjective.present? && amenities.present?
        [size_adjective, room_type_number_and_destination, amenities].compact.join(" ").html_safe

      elsif room_type_number_and_destination.present? && amenities.present?
        [room_type_number_and_destination, amenities].compact.join(" ").html_safe

      elsif room_type_number_and_destination.present? && size_adjective.present?
        [size_adjective, room_type_number_and_destination].compact.join(" ").html_safe

      elsif room_type_number_and_destination.present?
        room_type_number_and_destination

      end
    end


    # Shared methods

    def t(key, options={})
      value = I18n.t("rooms.title_generator.#{key}")
      key = "#{key}.#{sample(value.keys)}" if value.is_a?(Hash)
      I18n.t("rooms.title_generator.#{key}", options.merge({ locale: locale }))
    end

    # Translation Helpers
    def room_type
      @room_type ||= I18n.t("room_types.#{room.room_type.type}", locale: locale)
    end

    def destination
      @destination ||= room.destination.name_translations[locale] || room.destination.name_translations["en"]
    end

    # Sentences

    def size_adjective
      # For properties less than 500sq ft/50 sqm
      small_adjective = I18n.t("rooms.title_generator.adjectives.small", locale: locale).map{ |key, value| value }
      small_adjective = small_adjective.sample

      # For properties 500-1000 sq ft/ 50-100 sqm
      medium_adjective = I18n.t("rooms.title_generator.adjectives.medium", locale: locale).map{ |key, value| value }
      medium_adjective = medium_adjective.sample

      # For properties above 1000 sf/100 sqm
      large_adjective = I18n.t("rooms.title_generator.adjectives.large", locale: locale).map{ |key, value| value }
      large_adjective = large_adjective.sample


      if room.surface.present? && room.surface_unit.present? && room.surface_unit == "metric"
        case
          when room.surface >= 100                        then large_adjective
          when room.surface >= 50 && room.surface < 100   then medium_adjective
          when room.surface < 50                          then small_adjective
        end

      elsif room.surface.present? && room.surface_unit.present? && room.surface_unit == "imperial"
        case
          when room.surface >= 1000                        then large_adjective
          when room.surface >= 500 && room.surface < 1000  then medium_adjective
          when room.surface < 500                          then small_adjective
        end

      else
        return nil
      end
    end


    def room_type_number_and_destination
      if room.destination.present? && room.number_of_rooms && room.room_type.present?
        case
          when room.number_of_rooms >= 1   then t("number_type_destination", room_type: room_type, number_of_rooms: room.number_of_rooms, destination: destination)
          when room.number_of_rooms == 0  then t("studio_type_destination", room_type: room_type, destination: destination)
        end

      elsif room.room_type && room.number_of_rooms && room.neighborhood.present? && room.city.present?
        case
          when room.number_of_rooms >= 1   then t("number_type_neighborhood_city", room_type: room_type, number_of_rooms: room.number_of_rooms, neighborhood: room.neighborhood, city: room.city)
          when room.number_of_rooms == 0  then t("studio_type_neighborhood_city", room_type: room_type, neighborhood: room.neighborhood, city: room.city)
        end

      elsif room.destination.present? && room.number_of_rooms
        t("number_destination", number_of_rooms: room.number_of_rooms, destination: destination)

      elsif room.number_of_rooms && room.room_type.present?
        t("number_type", number_of_rooms: room.number_of_rooms, room_type: room_type)

      else
        return nil
      end
    end

    def amenities
      tmp = amenities_list

      if tmp.present?
        return t("amenities.with") + " " + tmp.to_sentence
      else
        return nil
      end

    end

    def amenities_list
      tmp = []
      tmp << t("amenities.aircon") if room.airconditioning?
      tmp << t("amenities.parking") if room.parking
      tmp << t("amenities.pool") if room.pool
      tmp << t("amenities.gym") if room.gym
      tmp << t("amenities.doorman") if room.doorman
      tmp << t("amenities.balcony") if room.balcony
      tmp << t("amenities.breakfast_provided") if room.breakfast
      tmp
    end

  end
end

______

require 'spec_helper'

describe Rooms::TitleGenerator do

  let!(:room) { create(:room) }
  let(:locale) { 'en' }
  let(:generator) { Rooms::TitleGenerator.new(room, locale) }

  describe "#generate" do
    context "room_type_number_and_destination.present? && size_adjective.present? && amenities.present?" do
      it "returns the correct title for the specified large room with some amenities" do
        sentence = /(?:Family-friendly|Group-friendly|Perfect|Spacious|Large|Grand|Very|Spacious|Awesome|Wonderful|Fantastic|Amazing|Superb|Marvellous|Stunning|Incredible|Fine|Excellent|Fab|Superb) 4 Bedroom Apartment in Chinatown with Pool and Gym/
        room.surface = 120
        room.surface_unit = "metric"
        room.number_of_rooms = 4
        room.room_type.type = "Apartment"
        room.destination.name = "Chinatown"
        room.pool = true
        room.gym = true
        expect(generator.send(:generate)).to match (sentence)
      end
    end

    context "room_type_number_and_destination.present? && amenities.present? - without size" do
      it "returns the correct title for the specified room with some amenities" do
        sentence = "4 Bedroom Apartment in Chinatown with Pool and Gym"
        room.surface = nil
        room.surface_unit = nil
        room.number_of_rooms = 4
        room.room_type.type = "Apartment"
        room.destination.name = "Chinatown"
        room.pool = true
        room.gym = true
        expect(generator.send(:generate)).to match (sentence)
      end
    end

    context "room_type_number_and_destination.present? && size_adjective.present? - without amenities" do
      it "returns the correct title for for the specified small room" do
        sentence = /(?:Cozy|Warm|Welcoming|Compact|Comfy|Comfortable|Intimate|Agreeable|Pleasant|Delightful|Charming|Lovely|Convenient|Accessible) Studio Apartment in Chinatown/
        room.surface = 40
        room.surface_unit = "metric"
        room.number_of_rooms = 0
        room.room_type.type = "Apartment"
        room.destination.name = "Chinatown"
        expect(generator.send(:generate)).to match (sentence)
      end

      it "returns the correct title for the specified medium room" do
        sentence = /(?:Comfortable|Spacious|Welcoming|Comfortable|Large|Good-sized|Lovely|Charming|Well-spaced|Well-appointed|Wonderful|Beautiful|Great|Fantastic|Super|Friendly|Amazing|Unbeatable|Awesome) 2 Bedroom Apartment in Chinatown/
        room.surface = 80
        room.surface_unit = "metric"
        room.number_of_rooms = 2
        room.room_type.type = "Apartment"
        room.destination.name = "Chinatown"
        expect(generator.send(:generate)).to match (sentence)
      end

      it "returns the correct title for the specified large room" do
        sentence = /(?:Family-friendly|Group-friendly|Perfect|Spacious|Large|Grand|Very|Spacious|Awesome|Wonderful|Fantastic|Amazing|Superb|Marvellous|Stunning|Incredible|Fine|Excellent|Fab|Superb) 4 Bedroom Apartment in Chinatown/
        room.surface = 120
        room.surface_unit = "metric"
        room.number_of_rooms = 4
        room.room_type.type = "Apartment"
        room.destination.name = "Chinatown"
        expect(generator.send(:generate)).to match (sentence)
      end
    end

    context "room_type_number_and_destination.present? - without size or amenities" do
      it "returns the correct title for the room specified without a size" do
        sentence = "4 Bedroom Apartment in Chinatown"
        room.surface = nil
        room.surface_unit = nil
        room.number_of_rooms = 4
        room.room_type.type = "Apartment"
        room.destination.name = "Chinatown"
        expect(generator.send(:generate)).to eq (sentence)
      end
    end

    context "nil for required attributes" do
      it "returns nil if we have no suggested title to offer" do
        room.number_of_rooms = nil
        room.destination = nil
        room.room_type.type = nil
        room.neighborhood = nil
        room.city = nil
        room.surface = nil
        room.surface_unit = nil
        expect(generator.send(:generate)).to eq nil
      end
    end
  end

  describe "#size_adjective" do
    context "metric" do
      it "returns one of specified adjectives for 'small' property" do
        sentence = /(?:Cozy|Warm|Welcoming|Compact|Comfy|Comfortable|Intimate|Agreeable|Pleasant|Delightful|Charming|Lovely|Convenient|Accessible)/
        room.surface = 40
        room.surface_unit = "metric"
        expect(generator.send(:size_adjective)).to match (sentence)
      end

      it "returns one of specified adjectives for 'medium' property" do
        sentence = /(?:Comfortable|Spacious|Welcoming|Comfortable|Large|Good-sized|Lovely|Charming|Well-spaced|Well-appointed|Wonderful|Beautiful|Great|Fantastic|Super|Friendly|Amazing|Unbeatable|Awesome)/
        room.surface = 80
        room.surface_unit = "metric"
        expect(generator.send(:size_adjective)).to match (sentence)
      end

      it "returns one of specified adjectives for 'large' property" do
        sentence = /(?:Family-friendly|Group-friendly|Perfect|Spacious|Large|Grand|Very|Spacious|Awesome|Wonderful|Fantastic|Amazing|Superb|Marvellous|Stunning|Incredible|Fine|Excellent|Fab|Superb)/
        room.surface = 120
        room.surface_unit = "metric"
        expect(generator.send(:size_adjective)).to match (sentence)
      end
    end

    context "imperial" do
      it "returns one of specified adjectives for 'small' property" do
        sentence = /(?:Cozy|Warm|Welcoming|Compact|Comfy|Comfortable|Intimate|Agreeable|Pleasant|Delightful|Charming|Lovely|Convenient|Accessible)/
        room.surface = 400
        room.surface_unit = "imperial"
        expect(generator.send(:size_adjective)).to match (sentence)
      end

      it "returns one of specified adjectives for 'medium' property" do
        sentence = /(?:Comfortable|Spacious|Welcoming|Comfortable|Large|Good-sized|Lovely|Charming|Well-spaced|Well-appointed|Wonderful|Beautiful|Great|Fantastic|Super|Friendly|Amazing|Unbeatable|Awesome)/
        room.surface = 800
        room.surface_unit = "imperial"
        expect(generator.send(:size_adjective)).to match (sentence)
      end

      it "returns one of specified adjectives for 'large' property" do
        sentence = /(?:Family-friendly|Group-friendly|Perfect|Spacious|Large|Grand|Very|Spacious|Awesome|Wonderful|Fantastic|Amazing|Superb|Marvellous|Stunning|Incredible|Fine|Excellent|Fab|Superb)/
        room.surface = 1200
        room.surface_unit = "imperial"
        expect(generator.send(:size_adjective)).to match (sentence)
      end
    end

    context "no surface unit or measurement" do
      it "returns nil when no surface unit or measurement is given" do
        room.surface = nil
        room.surface_unit = nil
        expect(generator.send(:size_adjective)).to eq nil
      end
    end

  end

  describe "#room_type_number_and_destination" do
    it "returns the correct title when room has destination, # of rooms and also type with many bedrooms" do
      sentence = "2 Bedroom Apartment in Chinatown"
      room.number_of_rooms = 2
      room.room_type.type = "Apartment"
      room.destination.name = "Chinatown"
      expect(generator.send(:room_type_number_and_destination)).to eq (sentence)
    end

    it "returns the correct title when room has destination, # of rooms and also type with zero bedrooms (studio)" do
      sentence = "Studio Apartment in Chinatown"
      room.number_of_rooms = 0
      room.room_type.type = "Apartment"
      room.destination.name = "Chinatown"
      expect(generator.send(:room_type_number_and_destination)).to match (sentence)
    end

    it "returns the correct title when room has destination, # of rooms (but no type)" do
      sentence = "2 Bedroom Property in Chinatown"
      room.number_of_rooms = 2
      room.room_type = nil
      room.destination.name = "Chinatown"
      expect(generator.send(:room_type_number_and_destination)).to eq (sentence)
    end

    it "returns the correct title when room has number of rooms, neighborhood, city and room type" do
      sentence = "2 Bedroom Apartment in Chinatown, Singapore"
      room.number_of_rooms = 2
      room.destination = nil
      room.room_type.type = "Apartment"
      room.neighborhood = "Chinatown"
      room.city = "Singapore"
      expect(generator.send(:room_type_number_and_destination)).to eq (sentence)
    end

    it "returns the correct title when room has neighborhood, city and room type with zero bedrooms (studio)" do
      sentence = "Studio Apartment in Chinatown"
      room.number_of_rooms = 0
      room.destination = nil
      room.room_type.type = "Apartment"
      room.neighborhood = "Chinatown"
      room.city = "Singapore"
      expect(generator.send(:room_type_number_and_destination)).to match (sentence)
    end
  end

  describe "#amenities" do
    it "returns the correct sentence when room has all the specified amenities" do
      sentence = "with Aircon, Parking, Pool, Gym, Doorman, Balcony, and Breakfast-provided"
      room.airconditioning = true
      room.parking = true
      room.pool = true
      room.gym = true
      room.doorman = true
      room.breakfast = true
      room.balcony = true
      expect(generator.send(:amenities)).to match (sentence)
    end

    it "returns the correct sentence when room has only one specified amenities" do
      sentence = "with Breakfast-provided"
      room.breakfast = true
      expect(generator.send(:amenities)).to match (sentence)
    end


    it "returns the correct sentence when room has only one specified amenities" do
      room.airconditioning = nil
      room.parking = nil
      room.pool = nil
      room.gym = nil
      room.doorman = nil
      room.breakfast = nil
      room.balcony = nil
      expect(generator.send(:amenities)).to eq nil
    end
  end
end