require 'rails_helper'

RSpec.describe Promotions::BackfillChannel, type: :service do

  context "validation" do
    let(:backfill_channel) { Promotions::BackfillChannel.new() }
    context "on language" do

      context "valid" do
        after do
          backfill_channel.valid?
          expect(backfill_channel.errors[:language]).to be_empty
        end
        it 'should allow blank language value' do
          backfill_channel.language = ''
        end

        it 'should allow lowercase language values' do
          backfill_channel.language = 'na'
        end

        it 'should allow lowercase language values and strings with hyphens' do
          backfill_channel.language = 'cn-aw'
        end

        it 'should allow lowercase language values and strings with hyphens' do
          backfill_channel.language = 'znanwon-ahweoh'
        end
      end

      context "invalid" do
        after do
          backfill_channel.valid?
          expect(backfill_channel.errors[:language]).to eq(['Invalid language format. Acceptable languages should be a single language like en or en-gb'])
        end

        it 'should not allow commas in the language' do
          backfill_channel.language = 'na,we'
        end

        it 'should not allow commas or spaces in the language' do
          backfill_channel.language = 'na-wno, we'
        end

        it 'should not allow spaces in the language' do
          backfill_channel.language = 'na wewe'
        end

        it 'should not allow uppercase in the begining of the language' do
          backfill_channel.language = 'Na'
        end

        it 'should not allow uppercase in the language' do
          backfill_channel.language = 'aNaa'
        end

        it 'should not allow uppercase in the language' do
          backfill_channel.language = 'aw-aNaa'
        end
      end
    end
  end

  context "#create" do
    let(:invalid_backfill_channel) { Promotions::BackfillChannel.new }
    let(:backfill_channel) { Promotions::BackfillChannel.new(title: "title", description_raw: "description", priority: 1, image_url: "url", sponsored: false, active: false,  language: "", login: "test_login")}
    let(:response) { double }

    it 'returns false on validation error' do
      expect(invalid_backfill_channel.save).to be_falsey
    end

    context 'valid creation' do
      let(:expected_url) { '/admin/backfill_channels' }
      let(:expected_body) { '{"backfill_channel":{"id":null,"user_id":null,"login":"test_login","priority":1,"title":"title","image_url":"url","created_on":null,"updated_on":null,"inserted_at":null,"updated_at":null,"sponsored":false,"description_raw":"description","language":"","active":false}}'}
      let(:expected_headers) { { 'Content-Type' => 'application/json' } }

      before do
          expect(Promotions::BackfillChannel).to receive(:post).with(expected_url, { body: expected_body, headers: expected_headers }).and_return(response)
      end

      context 'hypeman success' do
        before do
          expect(response).to receive(:body).and_return({"backfill_channel" => {"id" => 'aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1', "user_id" => 2}}).at_least(1)
          expect(response).to receive(:success?).and_return(true).at_least(1)
        end
        it 'submits allowed values to endpoint' do
          expect(backfill_channel.save()).to eq(true)
        end
        it 'updates the channel\'s user_id' do
          backfill_channel.save()
          expect(backfill_channel.user_id).to eq(2)
        end
      end

      context 'lance bass error' do
        before do
          expect(response).to receive(:success?).and_return(false).at_least(1)
        end
        it 'returns false with server errors' do
          expect(backfill_channel.save()).to eq(false)
          expect(backfill_channel.errors[:base]).to eq(['Create failed in Hypeman'])
        end
      end

    end
  end

  context "#update" do
    let(:backfill_channel) { Promotions::BackfillChannel.from_attributes(id: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1', title: "title", description_raw: "description", priority: 1, image_url: "url", sponsored: false, active: false, user_id: 1, language: "", inserted_at: "2017-01-1T00:00:00Z", updated_at: "2017-01-1T00:00:00Z")}
    let(:response) { double }

    it 'returns false on validation error' do
      changes = {priority: 20}

      expect(backfill_channel.update(changes)).to eq(false)
    end

    context 'valid updates' do
      let(:changes) { { priority: 10, sponsored: true, title: 'New title', language: 'en', active: true} }
      let(:expected_url) { '/admin/backfill_channels/aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1' }
      let(:expected_body) { '{"backfill_channel":{"priority":10,"title":"New title","image_url":"url","sponsored":true,"description_raw":"description","active":true}}'}
      let(:expected_headers) { { 'Content-Type' => 'application/json' } }

      before do
        expect(Promotions::BackfillChannel).to receive(:put).with(expected_url, { body: expected_body, headers: expected_headers }).and_return(response)
      end

      context 'Hypeman success' do
        before do
          expect(response).to receive(:success?).and_return(true).at_least(1)
        end

        it 'submits allowed values to endpoint' do
          expect(backfill_channel.update(changes)).to eq(true)
        end

        it 'captures old state for #changes' do
          backfill_channel.update(changes)

          expect(backfill_channel.changes).to eq({
            "title" => {old_value: 'title', new_value: 'New title'},
            "priority" => {old_value: 1, new_value: 10},
            "sponsored" => {old_value: false, new_value: true},
            "active" => {old_value: false, new_value: true},
          })
        end
      end

      context 'hypeman error' do
        before do
          expect(response).to receive(:success?).and_return(false).at_least(1)
        end

        it 'returns false with server errors' do
          expect(backfill_channel.update(changes)).to eq(false)
          expect(backfill_channel.errors[:base]).to eq(['Update failed in Hypeman'])
        end
      end
    end
  end

  context "destroy" do
    let(:backfill_channel) { Promotions::BackfillChannel.from_attributes(id: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1', title: "title", description_raw: "description", priority: 1, image_url: "url", sponsored: false, active: false, user_id: 1, language: "")}
    let(:connection) { double }
    let(:response) { double }
    let(:expected_url) { '/admin/backfill_channels/aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1' }

    before do
      expect(Promotions::BackfillChannel).to receive(:delete).with(expected_url).and_return(response)
    end

    it 'returns false on validation error' do
      expect(response).to receive(:success?).and_return(false).twice
      expect(backfill_channel.destroy()).to eq(false)
    end

    context 'valid deletion' do
      context 'hypeman success' do
        it 'submits allowed values to endpoint' do
          expect(response).to receive(:success?).and_return(true).twice
          expect(backfill_channel.destroy()).to eq(true)
        end
      end

      context 'hypeman error' do
        before do
          expect(response).to receive(:success?).and_return(false).at_least(1)
        end
        it 'returns false with server errors' do
          expect(backfill_channel.destroy()).to eq(false)
          expect(backfill_channel.errors[:base]).to eq(['Delete failed in Hypeman'])
        end
      end

    end
  end
end
