require_relative '../spec_helper'
require_relative '../factories/organizations_contexts'

describe Carto::Api::UserPresenter do

  before(:each) do
    CartoDB::UserModule::DBService.any_instance.stubs(:enable_remote_db_user).returns(true)
  end

  describe '#current_viewer' do
    include_context 'organization with users helper'

    it 'displays full data for user administrator' do
      presentation = Carto::Api::UserPresenter.new(@carto_org_user_1, current_viewer: @carto_org_user_owner).to_poro
      expect(presentation.keys).to include :email
    end

    it 'displays full data for own user' do
      presentation = Carto::Api::UserPresenter.new(@carto_org_user_1, current_viewer: @carto_org_user_1).to_poro
      expect(presentation.keys).to include :email
    end

    it 'displays filtered data for other users' do
      presentation = Carto::Api::UserPresenter.new(@carto_org_user_1, current_viewer: @carto_org_user_2).to_poro
      expect(presentation.keys).to_not include :email
    end

    it 'displays filtered data for public' do
      presentation = Carto::Api::UserPresenter.new(@carto_org_user_1).to_poro
      expect(presentation.keys).to_not include :email
    end
  end

  it "Compares old and new ways of 'presenting' user data" do
    Delorean.time_travel_to('2018-01-15')

    bypass_named_maps

    # Non-org user
    user = create_user({
        email: 'example@carto.com',
        username: 'example',
        password: 'example123',
        name: "my example name",
        sync_tables_enabled: true,
        private_tables_enabled: true,
        twitter_datasource_enabled: true,
        twitter_datasource_block_size: 1000,
        twitter_datasource_block_price: 10,
        twitter_datasource_quota: 70000,
        soft_twitter_datasource_limit: true,
        public_visualization_count: 1,
        all_visualization_count: 2,
        job_role: "Developer",
        company: "test",
        phone: "123",
        industry: "Academic and Education",
        period_end_date: Time.parse('2018-01-01'),
        account_type: 'ENTERPRISE LUMP-SUM'
      })

    # Some sample data
    data_import_id = '11111111-1111-1111-1111-111111111111'
    SequelRails.connection.run(%Q{
      INSERT INTO data_imports("data_source","data_type","table_name","state","success","logger","updated_at",
        "created_at","tables_created_count",
        "table_names","append","id","table_id","user_id",
        "service_name","service_item_id","stats","type_guessing","quoted_fields_guessing","content_guessing","server","host",
        "resque_ppid","upload_host","create_visualization","user_defined_limits")
        VALUES('test','url','test','complete','t','11111111-1111-1111-1111-111111111112',
          '2015-03-17 00:00:00.94006+00','2015-03-17 00:00:00.810581+00','1',
          'test','f','#{data_import_id}','11111111-1111-1111-1111-111111111113',
          '#{user.id}','public_url', 'test',
          '[{"type":".csv","size":5015}]','t','f','t','test','0.0.0.0','13204','test','f','{"twitter_credits_limit":0}');
      })
    SequelRails.connection.run(%Q{
      INSERT INTO geocodings("table_name","processed_rows","created_at","updated_at","formatter","state",
        "id","user_id",
        "cache_hits","kind","geometry_type","processable_rows","real_rows","used_credits",
        "data_import_id"
        ) VALUES('importer_123456','197','2015-03-17 00:00:00.279934+00','2015-03-17 00:00:00.536383+00','field_1','finished',
          '11111111-1111-1111-1111-111111111114','#{user.id}','0','admin0','polygon','195','0','0',
          '#{data_import_id}');
      })

    create_table( { user_id: user.id, name: 'table1' } )
    create_table( { user_id: user.id, name: 'table2', privacy: Carto::UserTable::PRIVACY_PUBLIC } )

    feature_flag1 = create(:feature_flag, id: 1, name: 'ff1')
    feature_flag2 = create(:feature_flag, id: 2, name: 'ff2')
    user.update_feature_flags([ feature_flag1.id.to_s, feature_flag2.id.to_s ])
    user.save.reload

    compare_data(user.data, Carto::Api::UserPresenter.new(Carto::User.find(user.id)).data, false, false)

    # Now org user, organization and another member

    owner = create_user({
        email: 'owner@carto.com',
        username: 'owner',
        password: 'owner123',
        name: "owner name",
        sync_tables_enabled: true,
        private_tables_enabled: true,
        twitter_datasource_enabled: true,
        twitter_datasource_block_size: 1000,
        twitter_datasource_block_price: 10,
        twitter_datasource_quota: 70000,
        soft_twitter_datasource_limit: true,
        public_visualization_count: 1,
        all_visualization_count: 2,
        job_role: "Developer",
        company: "test",
        phone: "123",
        industry: "Academic and Education",
        period_end_date: Time.parse('2018-01-01'),
        account_type: 'ENTERPRISE LUMP-SUM'
      })

    organization = Carto::Organization.create(quota_in_bytes: 200.megabytes, name: 'testorg', seats: 5)
    user_org = CartoDB::UserOrganization.new(organization.id, owner.id)
    user_org.promote_user_to_admin
    organization.reload
    owner.reload

    user2 = create_user({
        email: 'example2@carto.com',
        username: 'example2',
        password: 'example123',
        account_type: 'ORGANIZATION USER'
      })

    user2.organization = organization
    user2.save
    user2.reload
    organization.reload

    compare_data(owner.data, Carto::Api::UserPresenter.new(Carto::User.find(owner.id)).data, true)

    SequelRails.connection.run( %Q{ DELETE FROM geocodings } )
    SequelRails.connection.run( %Q{ DELETE FROM data_imports } )
    user.destroy
    organization.destroy
    Delorean.back_to_the_present
  end

  protected

  def compare_data(original_old_data, new_data, org_user = false, mobile_sdk_enabled = false)
    old_data = add_new_keys(original_old_data)
    # INFO: new organization presenter now doesn't contain users
    old_data[:organization].delete(:users) if old_data[:organization]

    # TODO: This fails at CI server, until there's time to research...
    #new_data.should eq old_data

    # To detect deltas not migrated to new presenter
    new_data.keys.sort.should == old_data.keys.sort

    new_data[:id].should == old_data[:id]
    new_data[:email].should == old_data[:email]
    new_data[:name].should == old_data[:name]
    new_data[:username].should == old_data[:username]
    new_data[:account_type].should == old_data[:account_type]
    new_data[:table_quota].should == old_data[:table_quota]
    new_data[:public_map_quota].should == old_data[:public_map_quota]
    new_data[:public_dataset_quota].should == old_data[:public_dataset_quota]
    new_data[:private_map_quota].should == old_data[:private_map_quota]
    new_data[:regular_api_key_quota].should == old_data[:regular_api_key_quota]
    new_data[:table_count].should == old_data[:table_count]
    new_data[:public_visualization_count].should == old_data[:public_visualization_count]
    new_data[:public_privacy_visualization_count].should == old_data[:public_privacy_visualization_count]
    new_data[:link_privacy_visualization_count].should == old_data[:link_privacy_visualization_count]
    new_data[:password_privacy_visualization_count].should == old_data[:password_privacy_visualization_count]
    new_data[:private_privacy_visualization_count].should == old_data[:private_privacy_visualization_count]
    new_data[:all_visualization_count].should == old_data[:all_visualization_count]
    new_data[:visualization_count].should == old_data[:visualization_count]
    new_data[:failed_import_count].should == old_data[:failed_import_count]
    new_data[:success_import_count].should == old_data[:success_import_count]
    new_data[:import_count].should == old_data[:import_count]
    new_viz_date = new_data[:last_visualization_created_at].to_s
    old_viz_date = old_data[:last_visualization_created_at].to_s
    Time.parse(new_viz_date).should eq Time.parse(old_viz_date) unless old_viz_date.blank? && new_viz_date.blank?
    new_data[:quota_in_bytes].should == old_data[:quota_in_bytes]
    new_data[:db_size_in_bytes].should == old_data[:db_size_in_bytes]
    new_data[:db_size_in_megabytes].should == old_data[:db_size_in_megabytes]
    new_data[:remaining_table_quota].should == old_data[:remaining_table_quota]
    new_data[:remaining_byte_quota].should == old_data[:remaining_byte_quota]
    new_data[:geocoding].should == old_data[:geocoding]
    new_data[:here_isolines].should == old_data[:here_isolines]
    new_data[:twitter].should == old_data[:twitter]
    new_data[:billing_period].should == old_data[:billing_period]
    new_data[:next_billing_period].should == old_data[:next_billing_period]
    new_data[:max_layers].should == old_data[:max_layers]
    new_data[:api_key].should == old_data[:api_key]
    new_data[:layers].should == old_data[:layers]
    new_data[:trial_ends_at].should == old_data[:trial_ends_at]
    new_data[:upgraded_at].should == old_data[:upgraded_at]
    new_data[:show_trial_reminder].should == old_data[:show_trial_reminder]
    new_data[:show_upgraded_message].should == old_data[:show_upgraded_message]
    new_data[:actions].should == old_data[:actions]
    new_data[:notification].should == old_data[:notification]
    new_data[:avatar_url].should == old_data[:avatar_url]
    new_data[:new_dashboard_enabled].should == old_data[:new_dashboard_enabled]
    new_data[:feature_flags].should == old_data[:feature_flags]
    new_data[:base_url].should == old_data[:base_url]
    new_data[:geocoder_provider].should == old_data[:geocoder_provider]
    new_data[:isolines_provider].should == old_data[:isolines_provider]
    new_data[:routing_provider].should == old_data[:routing_provider]
    new_data[:mfa_configured].should == old_data[:mfa_configured]
    new_data[:is_enterprise].should == old_data[:is_enterprise]
    new_data[:unverified].should == old_data[:unverified]

    if org_user
      new_data[:organization].keys.sort.should == old_data[:organization].keys.sort
      # rubocop:disable Lint/Void

      # This is an implicit test of OrganizationPresenter...
      # INFO: we have a weird error sometimes running builds that fails comparing dates despite having equal value...
      # > Diff:2015-06-23 17:27:02 +0200.==(2015-06-23 17:27:02 +0200) returned false even though the diff between
      #   2015-06-23 17:27:02 +0200 and 2015-06-23 17:27:02 +0200 is empty. Check the implementation of
      #   2015-06-23 17:27:02 +0200.==.
      new_data[:organization][:created_at].should == old_data[:organization][:created_at]
      new_data[:organization][:description].should == old_data[:organization][:description]
      new_data[:organization][:discus_shortname].should == old_data[:organization][:discus_shortname]
      new_data[:organization][:display_name].should == old_data[:organization][:display_name]
      new_data[:organization][:id].should == old_data[:organization][:id]
      new_data[:organization][:name].should == old_data[:organization][:name]
      new_data[:organization][:owner][:id].should == old_data[:organization][:owner][:id]
      new_data[:organization][:owner][:username].should == old_data[:organization][:owner][:username]
      new_data[:organization][:owner][:avatar_url].should == old_data[:organization][:owner][:avatar_url]
      new_data[:organization][:owner][:email].should == old_data[:organization][:owner][:email]
      new_data[:organization][:quota_in_bytes].should == old_data[:organization][:quota_in_bytes]
      new_data[:organization][:geocoding_quota].should == old_data[:organization][:geocoding_quota]
      new_data[:organization][:here_isolines_quota].should == old_data[:organization][:here_isolines_quota]
      new_data[:organization][:mapzen_routing_quota].should == old_data[:organization][:mapzen_routing_quota]
      new_data[:organization][:map_views_quota].should == old_data[:organization][:map_views_quota]
      new_data[:organization][:twitter_datasource_quota].should == old_data[:organization][:twitter_datasource_quota]
      new_data[:organization][:map_view_block_price].should == old_data[:organization][:map_view_block_price]
      new_data[:organization][:geocoding_block_price].should == old_data[:organization][:geocoding_block_price]
      new_data[:organization][:here_isolines_block_price].should == old_data[:organization][:here_isolines_block_price]
      new_data[:organization][:mapzen_routing_block_price].should == old_data[:organization][:mapzen_routing_block_price]
      new_data[:organization][:seats].should == old_data[:organization][:seats]
      new_data[:organization][:twitter_username].should == old_data[:organization][:twitter_username]
      new_data[:organization][:location].should == old_data[:organization][:location]
      # Same as [:organization][:created_at] issue above
      # TODO Skipped organization.created_at due to Rails 4 TZ issues
      # new_data[:organization][:updated_at].to_s.should == old_data[:organization][:updated_at].to_s
      #owner is excluded from the users list
      new_data[:organization][:website].should == old_data[:organization][:website]
      new_data[:organization][:avatar_url].should == old_data[:organization][:avatar_url]
      new_data[:geocoder_provider].should == old_data[:geocoder_provider]
      new_data[:isolines_provider].should == old_data[:isolines_provider]
      new_data[:routing_provider].should == old_data[:routing_provider]
      # rubocop:enable Lint/Void
    end

    if mobile_sdk_enabled
      new_data[:mobile_apps].keys.sort.should == old_data[:mobile_apps].keys.sort

      new_data[:mobile_apps][:mobile_xamarin].should = new_data[:mobile_apps].mobile_xamarin
      new_data[:mobile_apps][:mobile_custom_watermark].should = new_data[:mobile_apps].mobile_custom_watermark
      new_data[:mobile_apps][:mobile_offline_maps].should = new_data[:mobile_apps].mobile_offline_maps
      new_data[:mobile_apps][:mobile_gis_extension].should = new_data[:mobile_apps].mobile_gis_extension
      new_data[:mobile_apps][:mobile_max_open_users].should = new_data[:mobile_apps].mobile_max_open_users
      new_data[:mobile_apps][:mobile_max_private_users].should = new_data[:mobile_apps].mobile_max_private_users
    end

    # TODO: Pending migration and testing of :real_table_count & :last_active_time

  end

  def add_new_keys(user_poro)
    new_poro = user_poro.dup.deep_merge(viewer: false)
    new_poro[:organization] = user_poro[:organization].deep_merge(viewer_seats: 0) if user_poro[:organization].present?
    new_poro[:mfa_configured] = false
    new_poro[:next_billing_period] = Time.parse('2018-02-01')
    new_poro[:is_enterprise] = true
    new_poro[:do_enabled] = false
    new_poro[:do_bq_project] = nil
    new_poro[:do_bq_dataset] = nil
    new_poro
  end

  def create_org(org_name, org_quota, org_seats)
    Carto::Organization.create!(name: org_name, quota_in_bytes: org_quota, seats: org_seats)
  end

end
