require 'test_helper'

class Logic::ProviderUpgradeTest < ActiveSupport::TestCase

  def setup
    @provider = Factory :provider_account
    @power1M = Factory :published_plan, :system_name => 'power1M', :issuer => Account.master.services.first
    @pro = Factory :published_plan, :system_name => 'pro3M', :issuer => Account.master.services.first
    @enterprise = Factory :published_plan, :system_name => 'super_enterprise2020xl', :issuer => Account.master.services.first
    @base = Factory :published_plan, :system_name => 'base', :issuer => Account.master.services.first
  end

  def test_hideable_switches
    all_visible_switches = []
    filtered_switches    = []

    Logic::ProviderUpgrade.stub_const(:THREESCALE_VISIBLE_SWITCHES, []) do
      Settings::Switch.any_instance.stubs(:hideable?).returns(true)
      assert_not_empty (all_visible_switches = @provider.hideable_switches)

      Settings::Switch.any_instance.stubs(:hideable?).returns(false)
      assert_empty @provider.hideable_switches
    end

    name, _switch = @provider.settings.switches.first

    Logic::ProviderUpgrade.stub_const(:THREESCALE_VISIBLE_SWITCHES, [name.to_s]) do
      Settings::Switch.any_instance.stubs(:hideable?).returns(true)
      assert_not_empty (filtered_switches = @provider.hideable_switches)
    end
    
    assert (all_visible_switches.count - 1) == filtered_switches.count
  end

  test 'first plan with switch' do
    assert_kind_of ApplicationPlan, @provider.first_plan_with_switch('finance')
    assert_nil @provider.first_plan_with_switch('bananas')
  end

  test 'upgrade from base to power1M' do
    @provider.stubs(:credit_card_stored?).returns(true)
    @provider.upgrade_to_provider_plan!(@power1M)

    assert_equal 'power1M', @provider.reload.bought_cinstance.plan.system_name
    assert @provider.settings.finance.visible?, 'Finance should be visible on Power1M'
  end

  test 'upgrade from base to enterprise' do
    @provider.stubs(:credit_card_stored?).returns(true)
    @provider.force_upgrade_to_provider_plan!(@enterprise)

    assert_equal 'super_enterprise2020xl', @provider.reload.bought_cinstance.plan.system_name
    assert_equal 'enterprise', @provider.settings.product
  end

  test 'raises if not credit_card_stored?' do
    @provider.stubs(:credit_card_stored?).returns(false)
    assert_raises(RuntimeError) { @provider.upgrade_to_provider_plan!(@power1M) }
  end

  test 'raises if trying to upgrade to enterprise' do
    @provider.stubs(:credit_card_stored?).returns(true)
    assert_raises(RuntimeError) { @provider.upgrade_to_provider_plan!(@enterprise) }
  end

  test 'upgrade to inferior plans fails' do
    @provider.stubs(:credit_card_stored?).returns(true)

    @app = @provider.bought_cinstance
    @app.plan.update_attribute(:system_name, 'power1M')

    assert_raises(RuntimeError) { @provider.upgrade_to_provider_plan!(@base) }
  end

  test 'can call force_upgrade_to_provider_plan! with a master plan system_name' do
    @provider.force_upgrade_to_provider_plan!("power1M")
    assert_equal 'power1M', @provider.reload.bought_cinstance.plan.system_name
  end

  test 'force_upgrade_to_provider_plan! fails with a plan not from master' do
    assert_raises(RuntimeError){ @provider.force_upgrade_to_provider_plan!('foo') }
  end


  test 'force_to_change_plan!' do

    issuer = master_account.first_service!
    Factory(:application_plan, issuer: issuer, name: "plus", system_name: "plus")
    @provider.stubs(:provider_can_use?).with(:require_cc_on_signup).returns(false)


    plan = "plus"
    @provider.force_to_change_plan!(plan)
    switches_on = @provider.available_plans[plan]

    settings = @provider.settings
    switches_on.each do |switch|
      assert settings.send(switch).allowed?
    end

    switches_off = Logic::ProviderUpgrade::SWITCHES - switches_on
    switches_off.each do |switch|
      assert settings.send(switch).denied?
    end


    switches_show = Logic::ProviderUpgrade::THREESCALE_VISIBLE_SWITCHES & switches_on
    switches_show.each do |switch|
      assert settings.send(switch).visible?, "#{switch} switch is not visible"
    end

    plan = "base"
    @provider.force_to_change_plan!(plan)
    switches_on = @provider.available_plans[plan]

    settings = @provider.settings
    switches_on.each do |switch|
      assert settings.send(switch).allowed?
    end

    switches_off = Logic::ProviderUpgrade::SWITCHES - switches_on
    switches_off.each do |switch|
      assert settings.send(switch).denied?, "#{switch} switch is not denied"
    end

    switches_show = Logic::ProviderUpgrade::THREESCALE_VISIBLE_SWITCHES & switches_on
    switches_show.each do |switch|
      assert settings.send(switch).visible?, "#{switch} switch is not visible"
    end
  end

  test 'force_to_change_plan! for require_cc_on_signup switch' do
    @provider.stubs(:provider_can_use?).returns(true)
    assert @provider.settings.require_cc_on_signup.denied?

    @provider.stubs(:provider_can_use?).with(:require_cc_on_signup).returns(false)
    @provider.force_to_change_plan!('power1M')
    assert @provider.settings.require_cc_on_signup.visible?

    other_provider = FactoryGirl.create :provider_account
    assert other_provider.settings.require_cc_on_signup.denied?
    other_provider.stubs(:provider_can_use?).returns(true)

    other_provider.force_to_change_plan!('power1M')
    assert other_provider.settings.require_cc_on_signup.hidden?
  end

  test 'provider constraint is modified when upgrading' do
    assert constraints = @provider.build_provider_constraints(max_users: 1, max_services: 1)

    refute constraints.can_create_user?
    refute constraints.can_create_service?

    @provider.stubs(:credit_card_stored?).returns(true)
    @provider.upgrade_to_provider_plan!(@pro)

    assert constraints.can_create_user?
    assert constraints.can_create_service?
  end

  test 'provider constraint is modified when downgrading' do
    constraints = @provider.build_provider_constraints(max_users: 5, max_services: 5)

    @provider.stubs(:credit_card_stored?).returns(true)
    @provider.force_upgrade_to_provider_plan!(@base)

    refute constraints.can_create_user?
    refute constraints.can_create_service?
  end

  test 'first update switch, then limits' do
    constraints = @provider.create_provider_constraints!

    assert_difference(Audited.audit_class.method(:count), +2) do
      ProviderConstraints.with_auditing do
        assert constraints.auditing_enabled, 'auditing should be enabled'
        @provider.force_upgrade_to_provider_plan!(@pro)
      end
    end

    switch_audit, upgrade_audit = Audited.audit_class.order(:id).last(2)

    assert_equal 'Upgrading max_services because of switch is enabled.', switch_audit.comment
    assert_equal 'Upgrading limits to match plan pro3M', upgrade_audit.comment

    assert_equal 3, constraints.max_services
  end

  test 'update_provider_constraints_to' do
    assert @provider.update_provider_constraints_to({max_users: 1}, 'updating users')
    assert @provider.update_provider_constraints_to({max_services: 1}, 'updating services')

    assert constraints = @provider.provider_constraints
    assert_equal 1, constraints.max_users
    assert_equal 1, constraints.max_services
  end

  test 'checking if available_plans on provider are a hash' do
    partner = FactoryGirl.create(:partner, system_name: 'appdirect')
    provider = FactoryGirl.create(:simple_provider, partner: partner)

    assert_equal %I[ free_appdirect basic_appdirect power-appdirect pro_appdirect enterprise_appdirect ], provider.available_plans.keys
  end

  test 'checking switches available for accounts signed up via different partner options' do
    partner = FactoryGirl.create(:partner)
    provider =  FactoryGirl.create(:simple_provider, partner: partner)

    partner.system_name = 'heroku'
    refute_includes provider.available_switches.map(&:name), :multiple_users

    partner.system_name = 'appdirect'
    refute_includes provider.available_switches.map(&:name), :multiple_users

    partner.system_name = 'redhat'
    assert_includes provider.available_switches.map(&:name), :multiple_users

    partner.system_name = ''
    assert_includes provider.available_switches.map(&:name), :multiple_users
  end
end
