=begin

require 'spec_helper'

# collissions with teacher's schedule?
describe LessonBooking do

  let(:user) { FactoryGirl.create(:user, stored_credit_card: false, remaining_free_lessons: 1, remaining_test_drives: 1) }
  let(:teacher_user) { FactoryGirl.create(:teacher_user) }
  let(:teacher) { teacher_user.teacher }
  let(:lesson_booking_slot_single1) { FactoryGirl.build(:lesson_booking_slot_single) }
  let(:lesson_booking_slot_single2) { FactoryGirl.build(:lesson_booking_slot_single) }
  let(:lesson_booking_slot_recurring1) { FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 2.days.from_now.wday) }
  let(:lesson_booking_slot_recurring2) { FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 3.days.from_now.wday) }
  let(:valid_single_slots) { [lesson_booking_slot_single1, lesson_booking_slot_single2] }
  let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }

  describe "suspend!" do
    it "should set status as well as update status of all associated lesson_sessions" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      booking.lesson_sessions[0].accept({accepter: teacher_user, message: "got it", slot: booking.lesson_booking_slots[0].id})
      booking.reload
      booking.active.should eql true
      booking.suspend!
      booking.errors.any?.should be false
      booking.reload
      booking.active.should eql false
      booking.status.should eql LessonBooking::STATUS_SUSPENDED
      booking.lesson_sessions.count.should eql 2
      booking.lesson_sessions.each do |lesson_session|
        lesson_session.status.should eql LessonBooking::STATUS_SUSPENDED
      end
    end
  end

  describe "bill_monthlies" do
    after do
      Timecop.return
    end

    it "empty" do
      LessonBooking.count.should eql 0
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 0
    end

    it "one" do
      day = Date.new(2016, 1, 1)
      time = day.to_time
      Timecop.freeze(time)
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
      booking.errors.any?.should be false

      LessonBooking.count.should eql 1
      LessonPackagePurchase.count.should eql 0
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1

      purchase = LessonPackagePurchase.first
      purchase.billing_error_reason.should eql "stripe"
      purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
      purchase.month.should eql 1
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql false
      purchase.billed_at.should be_nil
      purchase.billing_attempts.should eql 1
      purchase.post_processed.should eql false
      purchase.post_processed_at.should be_nil
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql false

      # don't advance time, but nothing should happen because last_billing time hasn't elapsed
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload
      purchase.billing_error_reason.should eql "stripe"
      purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
      purchase.month.should eql 1
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql false
      purchase.billed_at.should eql nil
      purchase.billing_attempts.should eql 1
      purchase.post_processed.should eql false
      purchase.post_processed_at.should be_nil
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql false

      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload

      purchase.billing_error_reason.should eql "stripe"
      purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
      purchase.month.should eql 1
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql false
      purchase.billed_at.should eql nil
      purchase.billing_attempts.should eql 2
      purchase.post_processed.should eql false
      purchase.post_processed_at.should be_nil
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql false

      user.card_approved(create_stripe_token, '78759', booking.id)
      user.save!

      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload
      purchase.month.should eql 1
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql true
      purchase.billed_at.should eql time
      # purchase.billing_error_reason.should be nil
      purchase.billing_attempts.should eql 3
      purchase.post_processed.should eql true
      purchase.post_processed_at.should eql time
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql true
    end

    it "advances to next month" do
      user.card_approved(create_stripe_token, '78759', nil)
      user.save!

      day = Date.new(2016, 1, 20)
      time = day.to_time
      Timecop.freeze(time)
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
      booking.errors.any?.should be false

      LessonBooking.count.should eql 1
      LessonPackagePurchase.count.should eql 0
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      LessonSession.count.should eql 2

      purchase = LessonPackagePurchase.first
      purchase.month.should eql 1
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql true
      purchase.billed_at.should eql time
      # purchase.billing_error_reason.should be nil
      purchase.billing_attempts.should eql 1
      purchase.post_processed.should eql true
      purchase.post_processed_at.should eql time
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql true

      day = Date.new(2016, 1, 27)
      time = day.to_time
      Timecop.freeze(time)

      LessonBooking.schedule_upcoming_lessons
      LessonSession.count.should eql 3
      LessonPackagePurchase.count.should eql 1
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 2

      purchase = LessonPackagePurchase.order(:month).last
      purchase.month.should eql 2
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql true
      purchase.billed_at.should eql time
      # purchase.billing_error_reason.should be nil
      purchase.billing_attempts.should eql 1
      purchase.post_processed.should eql true
      purchase.post_processed_at.should eql time
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql true
    end

    it "will suspend after enough tries" do
      day = Date.new(2016, 1, 1)
      time = day.to_time
      Timecop.freeze(time)
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
      booking.errors.any?.should be false

      LessonBooking.count.should eql 1
      LessonPackagePurchase.count.should eql 0
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1

      purchase = LessonPackagePurchase.first
      purchase.billing_error_reason.should eql "stripe"
      purchase.billing_error_detail.should include("Cannot charge a customer that has no active card")
      purchase.billing_attempts.should eql 1
      booking.is_suspended?.should be_false
      purchase.billed.should be false
      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload
      purchase.billing_attempts.should eql 2
      booking.reload
      booking.is_suspended?.should be_false
      purchase.billed.should be false

      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload
      purchase.billing_attempts.should eql 3
      booking.reload
      booking.is_suspended?.should be_false
      purchase.billed.should be false

      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload
      purchase.billing_attempts.should eql 4
      booking.reload
      booking.is_suspended?.should be_false
      purchase.billed.should be false

      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      LessonBooking.bill_monthlies
      LessonPackagePurchase.count.should eql 1
      purchase.reload
      purchase.billing_attempts.should eql 5
      booking.reload
      booking.is_suspended?.should be_true
      purchase.billed.should be false

      # now that it's suspended, let's unsuspend it
      user.card_approved(create_stripe_token, '78759', booking.id)
      user.save!

      day = day + 1
      time = day.to_time
      Timecop.freeze(time)
      purchase.bill_monthly(true)
      LessonPackagePurchase.count.should eql 1
      purchase.reload

      purchase.month.should eql 1
      purchase.year.should eql 2016
      purchase.lesson_booking.should eql booking
      purchase.teacher.should eql teacher_user
      purchase.user.should eql user
      purchase.billed.should eql true
      purchase.billed_at.should eql time
      # purchase.billing_error_reason.should be nil
      purchase.billing_attempts.should eql 6
      purchase.post_processed.should eql true
      purchase.post_processed_at.should eql time
      purchase.last_billing_attempt_at.should eql time
      purchase.sent_billing_notices.should eql true
      booking.reload
      booking.is_suspended?.should be_false
    end

    it "missed meetings deduct on next month" do
      # TODO.  Discuss with David a little more
    end
  end

  describe "billable_monthlies" do
    after do
      Timecop.return
    end

    it "empty" do
      LessonBooking.billable_monthlies(Time.now).count.should eql 0
    end

    it "one" do
      time = Date.new(2016, 1, 1)
      Timecop.freeze(time)
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
      booking.errors.any?.should be false

      now = Time.now
      billables = LessonBooking.billable_monthlies(now)
      billables.all.to_a.should eql [booking]
      LessonPackagePurchase.where(lesson_booking_id: booking.id).count.should eql 0
      # to make this billable monthly go away, we will need to create one LessonPackagePurchase; one for this month (because it's only one we have lessons in)
      # and further, mark them both as post_processed

      package = LessonPackagePurchase.create(user, booking, LessonPackageType.single, 2016, 1)

      LessonBooking.billable_monthlies(now).count.should eql 1

      package.post_processed = true
      package.save!

      LessonBooking.billable_monthlies(now).count.should eql 0
    end
  end

  describe "predicted_times_for_month" do
    after do
      Timecop.return
    end
    it "fills up month" do

      next_year = Time.now.year + 1
      jan1 = Date.new(next_year, 1, 1)
      jan31 = Date.new(next_year, 1, -1)
      Timecop.freeze(jan1)
      slot = valid_recurring_slots[0]
      slot.day_of_week = jan1.wday

      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
      times = booking.predicted_times_for_month(next_year, 1)[:times]
      times.length.should eql 5
      times[0].to_date.should eql (jan1)
      times[1].to_date.should eql (Date.new(next_year, 1, 8))
      times[2].to_date.should eql (Date.new(next_year, 1, 15))
      times[3].to_date.should eql (Date.new(next_year, 1, 22))
      times[4].to_date.should eql (Date.new(next_year, 1, 29))
    end

    it "fills up partial month" do
      next_year = Time.now.year + 1
      jan1 = Date.new(next_year, 1, 1)
      jan15 = Date.new(next_year, 1, 15)
      jan31 = Date.new(next_year, 1, -1)
      Timecop.freeze(jan15)
      slot = valid_recurring_slots[0]
      slot.day_of_week = jan1.wday

      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
      times = booking.predicted_times_for_month(next_year, 1)[:times]
      times.length.should eql 3
      times[0].to_date.should eql (Date.new(next_year, 1, 15))
      times[1].to_date.should eql (Date.new(next_year, 1, 22))
      times[2].to_date.should eql (Date.new(next_year, 1, 29))
    end

    it "let's assume JamKazam is messed up for a few weeks" do
      next_year = Time.now.year + 1
      jan1 = Date.new(next_year, 1, 1)
      jan15 = Date.new(next_year, 1, 15)
      jan31 = Date.new(next_year, 1, -1)
      Timecop.freeze(jan1)
      slot = valid_recurring_slots[0]
      slot.day_of_week = jan1.wday

      # book a session on jan1
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)

      # but don't run the computation of times per month for weeks
      Timecop.freeze(Date.new(next_year, 1, 23))
      times = booking.predicted_times_for_month(next_year, 1)
      times[:times].length.should eql 2
      times[:times][0].to_date.should eql (Date.new(next_year, 1, 1))
      times[:times][1].to_date.should eql (Date.new(next_year, 1, 29))
    end
  end

  describe "book_free" do

    it "allows long message to flow through chat" do

      user.has_free_lessons?.should be_true
      booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, Faker::Lorem.characters(10000))

      booking.errors.any?.should be false

      chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
      chat_message.should_not be_nil
      chat_message.message.should eq booking.description
    end

    it "prevents user without free lesson" do

      pending "free not supported"
      booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be false

      ChatMessage.count.should eq 1

      booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be true
      booking.errors[:user].should eq ["have no remaining free lessons"]

      ChatMessage.count.should eq 1
    end

    it "must have 2 lesson booking slots" do

      booking = LessonBooking.book_test_drive(user, teacher_user, [], "Hey I've heard of you before.")
      booking.errors.any?.should be true
      booking.errors[:lesson_booking_slots].should eq ["must have two times specified"]
    end

    it "must have well-formed booking slots" do
      bad_slot = FactoryGirl.build(:lesson_booking_slot_single, minute: nil)
      booking = LessonBooking.book_free(user, teacher_user, [lesson_booking_slot_single1, bad_slot], "Hey I've heard of you before.")
      booking.errors.any?.should be true
      booking.errors[:lesson_booking_slots].should eq ["is invalid"]
      bad_slot = booking.lesson_booking_slots[1]
      bad_slot.errors[:minute].should eq ["is not a number"]
    end
  end

  describe "book_test_drive" do
    it "works" do
      user.stored_credit_card = true
      user.save!
      booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be false
      booking.user.should eq user
      booking.teacher.should eq teacher_user
      booking.description.should eq ("Hey I've heard of you before.")
      booking.payment_style.should eq LessonBooking::PAYMENT_STYLE_ELSEWHERE
      booking.recurring.should eq false
      booking.lesson_length.should eq 30
      booking.lesson_type.should eq LessonBooking::LESSON_TYPE_TEST_DRIVE
      booking.lesson_booking_slots.length.should eq 2

      chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
      chat_message.should_not be_nil
      chat_message.message.should eq booking.description

      user.reload
      user.remaining_free_lessons.should eq 1
      user.remaining_test_drives.should eq 0
    end

    it "allows long message to flow through chat" do
      booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, Faker::Lorem.characters(10000))

      booking.errors.any?.should be false

      chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
      chat_message.should_not be_nil
      chat_message.message.should eq booking.description
    end

    it "prevents user without remaining test drives" do

      user.stored_credit_card = true
      user.save!

      booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be false
      ChatMessage.count.should eq 1
      user.reload
      user.remaining_test_drives.should eql 0

      booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be true
      booking.errors[:user].should eq ["have an in-progress or successful TestDrive with this teacher already"]

      ChatMessage.count.should eq 1
    end


    it "must have well-formed booking slots" do
      bad_slot = FactoryGirl.build(:lesson_booking_slot_single, minute: nil)
      booking = LessonBooking.book_test_drive(user, teacher_user, [lesson_booking_slot_single1, bad_slot], "Hey I've heard of you before.")
      booking.errors.any?.should be true
      booking.errors[:lesson_booking_slots].should eq ["is invalid"]
      bad_slot = booking.lesson_booking_slots[1]
      bad_slot.errors[:minute].should eq ["is not a number"]
    end
  end

  describe "book_normal" do
    it "works" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
      booking.errors.any?.should be false
      booking.user.should eq user
      booking.teacher.should eq teacher_user
      booking.description.should eq ("Hey I've heard of you before.")
      booking.payment_style.should eq LessonBooking::PAYMENT_STYLE_SINGLE
      booking.recurring.should eq false
      booking.lesson_length.should eq 60
      booking.lesson_type.should eq LessonBooking::LESSON_TYPE_PAID
      booking.lesson_booking_slots.length.should eq 2

      chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
      chat_message.should_not be_nil
      chat_message.message.should eq booking.description

      user.reload
      user.remaining_free_lessons.should eq 1
      user.remaining_test_drives.should eq 1
    end

    it "works with recurring slots" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
      booking.errors.any?.should be false
      booking.user.should eq user
      booking.teacher.should eq teacher_user
      booking.description.should eq ("Hey I've heard of you before.")
      booking.payment_style.should eq LessonBooking::PAYMENT_STYLE_WEEKLY
      booking.recurring.should eq true
      booking.lesson_length.should eq 60
      booking.lesson_type.should eq LessonBooking::LESSON_TYPE_PAID
      booking.lesson_booking_slots.length.should eq 2

      chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
      chat_message.should_not be_nil
      chat_message.message.should eq booking.description

      user.reload
      user.remaining_free_lessons.should eq 1
      user.remaining_test_drives.should eq 1
    end

      it "allows long message to flow through chat" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, Faker::Lorem.characters(10000), true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)

      booking.errors.any?.should be false

      chat_message = ChatMessage.where(lesson_session_id: booking.next_lesson.id).first
      chat_message.should_not be_nil
      chat_message.message.should eq booking.description
    end

    it "does not prevent user without remaining test drives" do
      booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be false

      ChatMessage.count.should eq 1

      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)

      booking.errors.any?.should be false

      ChatMessage.count.should eq 2
    end

    it "does not prevents user without free lesson" do

      booking = LessonBooking.book_free(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
      booking.errors.any?.should be false

      ChatMessage.count.should eq 1

      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
      booking.errors.any?.should be false

      ChatMessage.count.should eq 2
    end

    it "does not prevent user without a stored credit card" do
      user.stored_credit_card = false
      user.save!

      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
      booking.errors.any?.should be false
      booking.card_presumed_ok.should eq false
      booking.sent_notices.should eq false
    end


    it "must have well-formed booking slots" do
      bad_slot = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: nil)
      booking = LessonBooking.book_test_drive(user, teacher_user, [lesson_booking_slot_recurring1, bad_slot], "Hey I've heard of you before.")
      booking.errors.any?.should be true
      booking.errors[:lesson_booking_slots].should eq ["is invalid"]
      bad_slot = booking.lesson_booking_slots[1]
      bad_slot.errors[:day_of_week].should eq ["must be specified"]
    end
  end

  describe "find_bookings_needing_sessions" do
    after do
      Timecop.return
    end
    it "can detect missing lesson and schedules it 1 week out" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60)
      booking.lesson_sessions.length.should eql 1

      booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user)
      booking.errors.any?.should be false
      booking.reload
      booking.lesson_sessions.length.should eql 2

      lesson_session = booking.lesson_sessions[0]
      Timecop.freeze(lesson_session.music_session.scheduled_start)

      # causes find_bookings_needing_sessions to re-run
      booking.sync_lessons
      booking.reload
      booking.lesson_sessions.length.should eql 3

      # check that all the times make sense

      lesson1 = booking.lesson_sessions[0]
      lesson2 = booking.lesson_sessions[1]
      lesson3 = booking.lesson_sessions[2]
      lesson1.music_session.scheduled_start.to_i.should eql (lesson2.music_session.scheduled_start.to_i - (60 * 60 * 24 * 7))
      lesson1.music_session.scheduled_start.to_i.should eql (lesson3.music_session.scheduled_start.to_i - (60 * 60 * 24 * 14))

      Timecop.freeze(lesson2.music_session.scheduled_start)

      # causes find_bookings_needing_sessions to re-run
      booking.sync_lessons
      booking.reload
      booking.lesson_sessions.length.should eql 4

      # check that all the times make sense

      lesson4 = booking.lesson_sessions[3]
      lesson1.music_session.scheduled_start.to_i.should eql (lesson4.music_session.scheduled_start.to_i - (60 * 60 * 24 * 21))
    end

    it "ignores non-recurring" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
      booking.lesson_sessions.length.should eql 1

      booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], user)

      booking.errors.any?.should be true
      booking.errors[:accepter].should eql ["No one has been indicated as accepting the lesson"]
    end
  end

  describe "canceling" do

    after do
      Timecop.return
    end

    it "single session gets canceled before accepted" do

      booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      # avoid 24 hour problem

      UserMailer.deliveries.clear
      Timecop.freeze(7.days.ago)
      lesson_session.cancel({canceler: teacher_user, message: 'meh', slot: booking.default_slot.id, update_all: false})
      lesson_session.errors.any?.should be_false
      lesson_session.reload
      lesson_session.status.should eql LessonSession::STATUS_CANCELED
      lesson_session.reload
      booking.reload
      booking.status.should eql LessonSession::STATUS_CANCELED
      UserMailer.deliveries.length.should eql 1
    end

    it "single session gets canceled after accepted" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      lesson_session.reload
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      UserMailer.deliveries.clear
      Timecop.freeze(7.days.ago)
      lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: false})
      lesson_session.errors.any?.should be_false
      lesson_session.reload
      lesson_session.status.should eql LessonSession::STATUS_CANCELED
      booking.reload
      booking.status.should eql LessonSession::STATUS_CANCELED
      UserMailer.deliveries.length.should eql 2
    end

    it "recurring session gets canceled after accepted" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      booking.active.should eql false
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: true})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      lesson_session.reload
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
      booking.reload
      booking.active.should eql true
      booking.status.should eql LessonSession::STATUS_APPROVED

      UserMailer.deliveries.clear
      Timecop.freeze(7.days.ago)
      lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: false})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_CANCELED
      lesson_session.reload
      lesson_session.canceler.should eql user
      booking.reload
      booking.active.should eql true
      booking.status.should eql LessonSession::STATUS_APPROVED
      booking.canceler.should be_nil
      UserMailer.deliveries.length.should eql 2
    end

    it "recurring booking gets canceled after accepted" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      lesson_session.reload
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      UserMailer.deliveries.clear
      Timecop.freeze(7.days.ago)

      mailer = mock
      mailer.should_receive(:deliver_now).exactly(2).times
      UserMailer.should_receive(:student_lesson_booking_canceled).and_return(mailer)
      UserMailer.should_receive(:teacher_lesson_booking_canceled).and_return(mailer)
      UserMailer.should_receive(:student_lesson_canceled).exactly(0).times
      UserMailer.should_receive(:teacher_lesson_canceled).exactly(0).times

      lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: true})
      lesson_session.errors.any?.should be_false
      lesson_session.reload
      lesson_session.status.should eql LessonSession::STATUS_CANCELED
      booking.reload
      booking.status.should eql LessonSession::STATUS_CANCELED
      booking.canceler.should eql user
    end
  end
  describe "rescheduling" do

    it "initial slot is in the past" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)

      lesson_session = booking.lesson_sessions[0]

      initial_scheduled_time = lesson_session.scheduled_start

      counter = FactoryGirl.build(:lesson_booking_slot_single, preferred_day: Date.today  + 20)
      lesson_session.counter({proposer: user, slot: counter, message: 'ACtually, let\'s do this instead for just this one'})

      Timecop.travel(initial_scheduled_time + 1)

      lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id, update_all: false})
      booking.reload
      booking.status.should eql LessonBooking::STATUS_APPROVED
      booking.lesson_sessions.count.should eql 1
      lesson_session.errors.any?.should be_false
      lesson_session.reload
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      lesson_session.scheduled_start.should eql counter.scheduled_time(0)
    end

    it "non-recurring, accepted with new slot" do
      booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60)
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      counter = FactoryGirl.build(:lesson_booking_slot_single, hour: 16)
      lesson_session.counter({proposer: user, slot: counter, message: 'Does this work better?'})
      lesson_session.errors.any?.should be false
      lesson_session.status.should eql LessonSession::STATUS_COUNTERED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
      lesson_session.counter_slot.should eql counter
      booking.reload
      booking.counter_slot.should be_nil

      lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id, update_all: false})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      lesson_session.reload
      lesson_session.scheduled_start.should eql counter.scheduled_time(0)
      booking.reload
      booking.accepter.should eql teacher_user
      booking.counter_slot.should be_nil
    end

    it "recurring" do
      Timecop.freeze(Time.new(2016, 03, 4, 5, 0, 0))
      booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60)
      lesson_session = booking.lesson_sessions[0]
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)

      counter = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 2, update_all: true)
      lesson_session.counter({proposer: user, slot: counter, message: 'Does this work better?'})
      lesson_session.errors.any?.should be false
      lesson_session.status.should eql LessonSession::STATUS_REQUESTED
      lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
      booking.reload
      booking.counter_slot.should eql counter
      booking.counterer.should eql user
      booking.has_recurring_counter?.should be true
      booking.is_countered?.should be true

      # to help scoot out the 'created_at' of the lessons
      Timecop.freeze(Time.now + 10)

      lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      booking.reload
      booking.status.should eql LessonSession::STATUS_APPROVED
      booking.has_recurring_counter?.should be false
      booking.is_countered?.should be false

      lesson_session.reload
      lesson_session.scheduled_start.should eql counter.scheduled_time(0)

      lesson_session2 = booking.lesson_sessions.order(:created_at)[1]
      lesson_session2.scheduled_start.should eql counter.scheduled_time(1)

      # now it's approved, we have 2 sessions that are not yet completed with a time

      # we should be able to reschedule just one of the lessons
      counter2 = FactoryGirl.build(:lesson_booking_slot_single, day_of_week: 4)
      lesson_session.counter({proposer: user, slot: counter2, message: 'ACtually, let\'s do this instead for just this one'})
      lesson_session.errors.any?.should be false
      lesson_session.status.should eql LessonSession::STATUS_COUNTERED
      lesson_session.has_recurring_counter?.should be false
      booking.reload
      booking.status.should eql LessonSession::STATUS_APPROVED

      lesson_session.scheduled_start.should eql counter.scheduled_time(0)

      lesson_session.accept({accepter: teacher_user, message: 'OK, lets fix just this one', slot: counter2.id})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      booking.reload
      lesson_session.reload
      lesson_session2.reload
      lesson_session.scheduled_start.should eql counter2.scheduled_time(0)
      lesson_session2.scheduled_start.should eql counter.scheduled_time(1) # STILL ORIGINAL COUNTER!

      # we should be able to reschedule all of the lessons


      counter3 = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 5, update_all: true)
      lesson_session.counter({proposer: user, slot: counter3, message: 'ACtually, let\'s do this instead for just this one... again'})
      lesson_session.errors.any?.should be false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      lesson_session.reload
      lesson_session.has_recurring_counter?.should be true
      lesson_session2.reload
      lesson_session2.has_recurring_counter?.should be true
      lesson_session.scheduled_start.should eql counter2.scheduled_time(0)
      lesson_session2.scheduled_start.should eql counter.scheduled_time(1)
      booking.reload
      booking.counter_slot.should eql counter3


      lesson_session.accept({accepter: teacher_user, message: 'OK, lets fix all of them', slot: counter3.id})
      lesson_session.errors.any?.should be_false
      lesson_session.status.should eql LessonSession::STATUS_APPROVED
      booking.reload
      booking.counter_slot.should be_nil
      lesson_session.reload
      lesson_session2.reload
      lesson_session.reload
      lesson_session.has_recurring_counter?.should be false
      lesson_session2.reload
      lesson_session2.has_recurring_counter?.should be false
      lesson_session.created_at.should be < lesson_session2.created_at

      lesson_session.scheduled_start.should eql counter3.scheduled_time(0)
      lesson_session2.scheduled_start.should eql counter3.scheduled_time(1)

    end
  end
end

=end