text: # frozen_string_literal: true
  
  require 'rails_helper'
  
  RSpec.describe ProjectObserver do
    let(:contribution) { create(:contribution, key: 'should be updated', payment_method: 'should be updated', state: 'confirmed', confirmed_at: nil) }
    let(:project) do
      project = create(:project, state: 'draft', goal: 3000)
      create(:reward, project: project)
      project.update_attribute :state, :online
      project
    end
  
    let(:admin_user) do
      CatarseSettings[:email_payments] = 'admin@foo.com'
      create(:user, email: CatarseSettings[:email_payments])
    end
  
    let(:redbooth_user) do
      CatarseSettings[:email_redbooth] = 'foo@foo.com'
      create(:user, email: CatarseSettings[:email_redbooth])
    end
  
    let(:zendesk_user_atendimento) do
      CatarseSettings[:email_contact] = 'foo_contato@foo.com'
      create(:user, email: CatarseSettings[:email_contact])
    end
  
    subject { contribution }
  
    before do
      CatarseSettings[:support_forum] = 'http://support.com'
      CatarseSettings[:email_projects] = 'foo@foo.com'
      CatarseSettings[:facebook_url] = 'http://facebook.com/foo'
      CatarseSettings[:blog_url] = 'http://blog.com/foo'
      CatarseSettings[:company_name] = 'Catarse'
    end
  
    describe '#after_create' do
      
      subject { ProjectObserver.instance }
  
      context 'when supportive project is created' do
        let(:integrations_attributes) { [{ name: 'SOLIDARITY_SERVICE_FEE', data: { name: 'SOLIDARITY FEE NAME' } }] }
        let(:category) { create(:category) }
        let(:project) { create(:project, name: "NEW PROJECT NAME", service_fee: 0.04, mode: 'flex', category_id: category.id, integrations_attributes: integrations_attributes) }
      
        it 'should have called send create_event_to_state method' do
          expect(project).to receive(:create_event_to_state)
          subject.after_create(project)
        end
  
      end
    end
  
    describe '#before_save' do
      context 'when video_url changed' do
        let(:project) { create(:project, video_url: 'https://www.youtube.com/watch?v=9QveBbn7t_c', video_embed_url: 'embed_url') }
  
        it 'should clean embed_url when video_is null' do
          expect(project.video_embed_url.present?).to eq(true)
          project.video_url = nil
          project.save
          expect(project.video_embed_url.present?).to eq(false)
        end
      end
      context 'when project is new' do
        before do
          expect(project).to receive(:update_expires_at)
        end
  
        let(:project) { build(:project, state: 'draft') }
  
        it 'should call update_expires_at' do
          project.save(validate: false)
        end
      end
  
      context 'when project is being updated and online_days does not change' do
        before do
          expect(project).to_not receive(:update_expires_at)
        end
  
        let!(:project) { create(:project, state: 'draft', expires_at: Date.tomorrow) }
  
        it 'should not call update_expires_at' do
          project.save(validate: false)
        end
      end
  
      context 'when expires_at is nil and we have both online_at and online_days' do
        before do
          expect(project).to receive(:update_expires_at)
        end
  
        let!(:project) { create(:project, state: 'draft', online_days: 60) }
  
        it 'should not call update_expires_at' do
          project.save(validate: false)
        end
      end
    end
  
    describe '#after_save' do
      let(:project) { build(:project, state: 'draft') }
  
      context 'common integration' do
        before do
          expect(project).to receive(:index_on_common)
        end
        it 'should call index on common' do
          project.update_attribute(:name, 'foo bar')
        end
      end
  
  
      context 'when we change the video_url' do
        let(:project) { create(:project, video_url: 'http://vimeo.com/11198435', state: 'draft') }
        before do
          expect(ProjectDownloaderWorker).to receive(:perform_async).with(project.id).never
        end
        it 'should call project downloader' do
          project.save(validate: false)
        end
      end
    end
  
    describe "#from_draft_to_online" do
      context 'expect that update expires_at and audited data' do
        let(:project) { create(:project, state: 'draft') }
        it do
          expect(project).to receive(:update_expires_at).at_least(:once).and_return(true)
          expect(project).to receive(:update_attributes).with(
            published_ip: project.user.current_sign_in_ip,
            audited_user_name: project.user.name,
            audited_user_cpf: project.user.cpf,
            audited_user_phone_number: project.user.phone_number
          ).and_return(true)
          project.push_to_online
        end
      end
  
      context 'expect call worker to broadcast new project online to followers' do
        let(:project) { create(:project, state: 'draft') }
        it do
          expect(UserBroadcastWorker).to receive(:perform_async).with(follow_id: project.user_id, template_name: 'follow_project_online', project_id: project.id)
          project.push_to_online
        end
      end
  
      context 'expect call worker to update fb cache' do
        let(:project) { create(:project, state: 'draft') }
        it do
          expect(FacebookScrapeReloadWorker).to receive(:perform_async).with(project.direct_url)
          project.push_to_online
        end
      end
  
      context 'expect call worker to schedule project metrics storage' do
        let(:project) { create(:project, state: 'draft') }
        it do
          expect(ProjectMetricStorageRefreshWorker).to receive(:perform_in).with(5.seconds, project.id)
          project.push_to_online
        end
      end
    end
  
    describe '#from_online_to_failed' do
      let(:project) do
        create_project({
          goal: 100,
          online_days: 30,
          state: 'online'
        }, {
          to_state: 'online',
          created_at: 3.days.ago
        })
      end
  
      let(:contribution_invalid) do
        create(:confirmed_contribution, value: 10, project: project)
      end
  
      let(:contribution_valid) do
        create(:confirmed_contribution, value: 10, project: project)
      end
  
      context 'should refund slip into balance' do
        let!(:payment_valid) do
          contribution_valid.payments.first
        end
  
        let!(:payment_slip) do
          p = contribution_invalid.payments.first
          p.update_column(:payment_method, 'BoletoBancario')
          p
        end
  
        before do
          Sidekiq::Testing.inline!
          contribution_invalid.user.bank_account.destroy
          project.update_attribute :online_days, 2
          expect(project).not_to receive(:notify_owner).with(:project_canceled)
          expect(DirectRefundWorker).to receive(:perform_async).with(payment_valid.id)
          expect(DirectRefundWorker).to receive(:perform_async).with(payment_slip.id).and_call_original
          expect(BalanceTransaction).to receive(:insert_contribution_refund).with(payment_slip.contribution_id)
        end
  
        it { project.finish }
      end
    end
  
    describe 'from_successful_to_rejected' do
      let(:project) do
        create_project({
          goal: 100,
          online_days:5,
          state: 'online'
        }, {
          to_state: 'online',
          created_at: 3.days.ago
        })
      end
  
      let!(:contribution) do
        create(:confirmed_contribution, value: 150, project: project)
      end
  
      before do
        #expect(BalanceTransaction).to receive(:insert_project_refund_contributions).with(project.id).and_call_original
        expect(BalanceTransaction).to receive(:insert_contribution_refund).with(contribution.id).and_call_original
        expect(BalanceTransaction).to receive(:insert_successful_project_transactions).with(project.id).and_call_original
  
        project.update_attribute(:online_days, 1)
        Sidekiq::Testing.inline!
  
        project.finish
  
        expect(project).to receive(:notify_owner).with(:project_canceled).and_call_original
        project.reject
      end
  
      it 'should refund contributons' do
        expect(contribution.payments.last.state).to eq('refunded')
        expect(contribution.balance_transactions.where(event_name: 'contribution_refund').count).to eq(1)
      end
  
      #it 'should remove project owner balance' do
      #  expect(project.balance_transactions.where(event_name: 'refund_contributions').count).to eq(1)
      #end
    end
  
    describe '#from_waiting_funds_to_successful' do
      before do
        admin_user
        redbooth_user
        project.notify_observers(:from_waiting_funds_to_successful)
      end
  
      it 'should create notification for admin' do
        expect(ProjectNotification.where(template_name: 'redbooth_task', user: redbooth_user, project_id: project.id).count).to eq(1)
      end
  
      it 'should create notification for project owner' do
        expect(ProjectNotification.where(template_name: 'project_success', user: project.user, project_id: project.id).count).to eq(5)
      end
    end
  end
  