=begin
require 'spec_helper'

describe TeacherPayment do

  let(:user) { FactoryGirl.create(:user) }
  let(:user2) { FactoryGirl.create(:user) }
  let(:teacher1_auth) { UserAuthorization.create(provider: 'stripe_connect', uid: stripe_account1_id, token: 'abc', refresh_token: 'abc', token_expiration: Date.today + 365, secret: 'secret') }
  let(:teacher2_auth) { UserAuthorization.create(provider: 'stripe_connect', uid: stripe_account2_id, token: 'abc', refresh_token: 'abc', token_expiration: Date.today + 365, secret: 'secret') }
  let(:teacher) { FactoryGirl.create(:user) }
  let(:teacher2) { FactoryGirl.create(:user) }
  let(:teacher_obj) { FactoryGirl.create(:teacher, user: teacher) }
  let(:teacher_obj2) { FactoryGirl.create(:teacher, user: teacher2) }

  let(:school_teacher) { FactoryGirl.create(:user) }
  let(:school_owner_teacher) { FactoryGirl.create(:teacher, user: school_teacher) }

  let(:test_drive_lesson) { testdrive_lesson(user, teacher) }
  let(:test_drive_lesson2) { testdrive_lesson(user2, teacher2) }
  let(:test_drive_distribution) { FactoryGirl.create(:teacher_distribution, lesson_session: test_drive_lesson, teacher: teacher, teacher_payment: nil, ready: false) }
  let(:test_drive_distribution2) { FactoryGirl.create(:teacher_distribution, lesson_session: test_drive_lesson2, teacher: teacher2, teacher_payment: nil, ready: false) }
  let(:normal_lesson_session) { normal_lesson(user, teacher) }
  let(:normal_distribution) { FactoryGirl.create(:teacher_distribution, lesson_session: normal_lesson_session, teacher: teacher, teacher_payment: nil, ready: false) }
  let(:school) { FactoryGirl.create(:school, user: school_teacher) }

  describe "pending_teacher_payments" do

    describe "normal teachers" do
      before(:each) do
        teacher_obj.touch
        teacher_obj2.touch
        teacher.teacher.stripe_account_id = stripe_account1_id
        teacher2.teacher.stripe_account_id = stripe_account2_id
      end
      it "empty" do
        TeacherPayment.pending_teacher_payments.count.should eql 0
      end

      it "one distribution" do
        teacher.should eql teacher_obj.user
        test_drive_distribution.touch

        teacher.user_authorizations.count.should eql 1
        user_auth = teacher.user_authorizations[0]
        user_auth.provider.should eql 'stripe_connect'
        payments = TeacherPayment.pending_teacher_payments
        payments.count.should eql 0

        test_drive_distribution.ready = true
        test_drive_distribution.save!
        test_drive_distribution.distributed.should be_false

        payments = TeacherPayment.pending_teacher_payments
        payments.count.should eql 1
        payments[0]['id'].should eql teacher.id
      end

      it "multiple teachers" do
        test_drive_distribution.touch
        test_drive_distribution2.touch

        payments = TeacherPayment.pending_teacher_payments
        payments.count.should eql 0

        test_drive_distribution.ready = true
        test_drive_distribution.save!
        test_drive_distribution2.ready = true
        test_drive_distribution2.save!

        payments = TeacherPayment.pending_teacher_payments
        payments.count.should eql 2
        payment_user_ids = payments.map(&:id)
        payment_user_ids.include? teacher.id
        payment_user_ids.include? teacher2.id
      end
    end

    describe "school teachers" do
      before(:each) do
        teacher_obj.touch
        teacher.teacher.stripe_account_id = stripe_account1_id
      end

      it "school distribution" do

        test_drive_distribution.school = school
        test_drive_distribution.save!

        payments = TeacherPayment.pending_teacher_payments
        payments.count.should eql 0

        test_drive_distribution.ready = true
        test_drive_distribution.save!

        payments = TeacherPayment.pending_teacher_payments
        payments.count.should eql 1
        payments[0]['id'].should eql teacher.id
      end

    end
  end

  describe "teacher_payments" do

    describe "normal teachers" do
      before(:each) do
        teacher_obj.touch
        teacher_obj2.touch
        teacher.teacher.stripe_account_id = stripe_account1_id
        teacher2.teacher.stripe_account_id = stripe_account2_id
      end


      it "empty" do
        TeacherPayment.teacher_payments
      end

      it "charges test drive" do
        test_drive_distribution.touch

        test_drive_distribution.ready = true
        test_drive_distribution.save!

        TeacherPayment.teacher_payments

        test_drive_distribution.reload
        test_drive_distribution.teacher_payment.should_not be_nil
        TeacherPayment.count.should eql 1

        payment = test_drive_distribution.teacher_payment

        if payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_detail
        end
        payment.teacher_payment_charge.billed.should eql true
        payment.teacher_payment_charge.amount_in_cents.should eql (1000 + 1000 * APP_CONFIG.stripe[:ach_pct]).round
        payment.teacher_payment_charge.fee_in_cents.should eql 0
        teacher_distribution = payment.teacher_payment_charge.distribution
        teacher_distribution.amount_in_cents.should eql 1000
        charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
        charge.amount.should eql (1000 + 1000 * APP_CONFIG.stripe[:ach_pct]).round
        charge.application_fee.should eql nil

        TeacherPayment.pending_teacher_payments.count.should eql 0
      end

      it "charges normal" do
        normal_distribution.touch

        normal_distribution.ready = true
        normal_distribution.save!
        UserMailer.deliveries.clear

        TeacherPayment.teacher_payments

        normal_distribution.reload
        normal_distribution.teacher_payment.should_not be_nil
        TeacherPayment.count.should eql 1

        payment = normal_distribution.teacher_payment

        if payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_detail
        end

        # only one confirm email to teacher
        UserMailer.deliveries.length.should eql 1
        payment.teacher_payment_charge.billed.should eql true
        payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
        payment.teacher_payment_charge.fee_in_cents.should eql 280
        payment.teacher_payment_charge.teacher.should eql teacher
        teacher_distribution = payment.teacher_payment_charge.distribution
        teacher_distribution.amount_in_cents.should eql 1000
        charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
        charge.amount.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
        charge.application_fee.should be_nil
      end


      it "charges multiple" do
        test_drive_distribution.touch
        test_drive_distribution.ready = true
        test_drive_distribution.save!
        normal_distribution.touch
        normal_distribution.ready = true
        normal_distribution.save!

        TeacherPayment.teacher_payments

        normal_distribution.reload
        normal_distribution.teacher_payment.should_not be_nil
        TeacherPayment.count.should eql 2

        payment = normal_distribution.teacher_payment

        if payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_detail
        end
        payment.teacher_payment_charge.billed.should eql true
        payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
        payment.teacher_payment_charge.fee_in_cents.should eql 280
        teacher_distribution = payment.teacher_payment_charge.distribution
        teacher_distribution.amount_in_cents.should eql 1000
        charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
        charge.amount.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
        charge.application_fee.should be_nil

        test_drive_distribution.reload
        payment = test_drive_distribution.teacher_payment

        if payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_detail
        end
        payment.teacher_payment_charge.billed.should eql true
        payment.teacher_payment_charge.amount_in_cents.should eql (1000 + 1000 * APP_CONFIG.stripe[:ach_pct]).round
        payment.teacher_payment_charge.fee_in_cents.should eql 0
        teacher_distribution = payment.teacher_payment_charge.distribution
        teacher_distribution.amount_in_cents.should eql 1000
        charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
        charge.amount.should eql 1000 + (1000 * APP_CONFIG.stripe[:ach_pct]).round
        charge.application_fee.should be_nil
      end


    end

    describe "school teachers" do
      before(:each) do
        teacher_obj.touch
        teacher.teacher.stripe_account_id = stripe_account1_id
        school_owner_teacher.touch
        school_teacher.teacher.stripe_account_id = stripe_account2_id
      end


      it "charges school" do
        teacher.touch
        normal_distribution.school = school
        normal_distribution.ready = true
        normal_distribution.save!

        UserMailer.deliveries.clear
        TeacherPayment.teacher_payments

        normal_distribution.reload
        normal_distribution.teacher_payment.should_not be_nil
        normal_distribution.teacher_payment.school.should eql school
        TeacherPayment.count.should eql 1

        payment = normal_distribution.teacher_payment

        if payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_reason
          puts payment.teacher_payment_charge.billing_error_detail
        end
        # one to school owner, one to teacher
        UserMailer.deliveries.length.should eql 2
        payment.teacher_payment_charge.billed.should eql true
        payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
        payment.teacher_payment_charge.fee_in_cents.should eql 330
        payment.teacher_payment_charge.user.should eql school.owner
        teacher_distribution = payment.teacher_payment_charge.distribution
        teacher_distribution.amount_in_cents.should eql 1000
        charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
        charge.destination.should_not be_nil
        charge.amount.should eql 675
        charge.application_fee.should be_nil
      end
    end

    describe "stripe mocked" do
      before {
        StripeMock.start
      }

      after { StripeMock.stop }
      describe "normal" do
        before {
          teacher_obj.touch
          teacher_obj2.touch
          teacher.teacher.stripe_account_id = stripe_account1_id
          teacher2.teacher.stripe_account_id = stripe_account2_id
        }

        it "failed payment, then success" do
          StripeMock.prepare_card_error(:card_declined)

          normal_distribution.touch
          normal_distribution.ready = true
          normal_distribution.save!

          TeacherPayment.teacher_payments

          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 1

          payment = normal_distribution.teacher_payment

          payment.teacher_payment_charge.billing_error_reason.should eql("card_declined")
          payment.teacher_payment_charge.billing_error_detail.should include("declined")

          payment.teacher_payment_charge.billed.should eql false
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 280
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000

          payment.teacher_payment_charge.stripe_charge_id.should be_nil

          StripeMock.clear_errors

          TeacherPayment.teacher_payments

          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 1

          # make sure the teacher_payment is reused, and charge is reused
          normal_distribution.teacher_payment.should eql(payment)
          normal_distribution.teacher_payment.teacher_payment_charge.should eql(payment.teacher_payment_charge)

          # no attempt should be made because a day hasn't gone by
          payment = normal_distribution.teacher_payment
          payment.teacher_payment_charge.billed.should eql false
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 280
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000

          # advance one day so that a charge is attempted again
          Timecop.freeze(Date.today + 2)

          TeacherPayment.teacher_payments
          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 1

          # make sure the teacher_payment is reused, and charge is reused
          normal_distribution.teacher_payment.should eql(payment)
          normal_distribution.teacher_payment.teacher_payment_charge.should eql(payment.teacher_payment_charge)

          # no attempt should be made because a day hasn't gone by
          payment = normal_distribution.teacher_payment
          payment.reload
          payment.teacher_payment_charge.billed.should eql true
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 280
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000
          charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
          charge.amount.should eql 726
        end



        it "charges multiple (with initial failure)" do
          StripeMock.prepare_card_error(:card_declined)

          test_drive_distribution.touch
          test_drive_distribution.ready = true
          test_drive_distribution.save!
          normal_distribution.touch
          normal_distribution.ready = true
          normal_distribution.save!

          TeacherPayment.teacher_payments

          TeacherPayment.count.should eql 1
          payment = TeacherPayment.first
          payment.teacher_payment_charge.billed.should be_false

          # advance one day so that a charge is attempted again
          Timecop.freeze(Date.today + 2)

          StripeMock.clear_errors
          TeacherPayment.teacher_payments

          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 2

          payment = normal_distribution.teacher_payment

          payment.teacher_payment_charge.billed.should eql true
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 280
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000
          charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
          charge.amount.should eql ((1000 * 0.72) + (1000 * 0.72) * APP_CONFIG.stripe[:ach_pct]).round

          test_drive_distribution.reload
          payment = test_drive_distribution.teacher_payment

          payment.teacher_payment_charge.billed.should eql true
          payment.teacher_payment_charge.amount_in_cents.should eql (1000 + 1000 * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 0
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000
          charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
          charge.amount.should eql 1000 + (1000 * APP_CONFIG.stripe[:ach_pct]).round
        end
      end

      describe "school" do
        before {
          teacher_obj.touch
          teacher.teacher.stripe_account_id = stripe_account1_id
          school_owner_teacher.touch
          school_teacher.teacher.stripe_account_id = stripe_account2_id
        }


        it "failed payment, then success (school)" do
          StripeMock.prepare_card_error(:card_declined)

          normal_distribution.school = school
          normal_distribution.ready = true
          normal_distribution.save!

          TeacherPayment.teacher_payments

          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 1

          payment = normal_distribution.teacher_payment

          payment.teacher_payment_charge.billing_error_reason.should eql("card_declined")
          payment.teacher_payment_charge.billing_error_detail.should include("declined")

          payment.teacher_payment_charge.billed.should eql false
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 330
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000

          payment.teacher_payment_charge.stripe_charge_id.should be_nil

          StripeMock.clear_errors

          TeacherPayment.teacher_payments

          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 1

          # make sure the teacher_payment is reused, and charge is reused
          normal_distribution.teacher_payment.should eql(payment)
          normal_distribution.teacher_payment.teacher_payment_charge.should eql(payment.teacher_payment_charge)

          # no attempt should be made because a day hasn't gone by
          payment = normal_distribution.teacher_payment
          payment.teacher_payment_charge.billed.should eql false
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 330
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000

          # advance one day so that a charge is attempted again
          Timecop.freeze(Date.today + 2)

          TeacherPayment.teacher_payments
          normal_distribution.reload
          normal_distribution.teacher_payment.should_not be_nil
          TeacherPayment.count.should eql 1

          # make sure the teacher_payment is reused, and charge is reused
          normal_distribution.teacher_payment.should eql(payment)
          normal_distribution.teacher_payment.teacher_payment_charge.should eql(payment.teacher_payment_charge)

          # no attempt should be made because a day hasn't gone by
          payment = normal_distribution.teacher_payment
          payment.reload
          payment.teacher_payment_charge.billed.should eql true
          payment.teacher_payment_charge.amount_in_cents.should eql ((1000 * 0.67) + (1000 * 0.67) * APP_CONFIG.stripe[:ach_pct]).round
          payment.teacher_payment_charge.fee_in_cents.should eql 330
          teacher_distribution = payment.teacher_payment_charge.distribution
          teacher_distribution.amount_in_cents.should eql 1000
          charge = Stripe::Charge.retrieve(payment.teacher_payment_charge.stripe_charge_id)
          charge.amount.should eql 675
        end
      end
    end

  end
end
=end