require 'rails_helper'

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

  context "validation" do
    let(:scheduled_vod) { Promotions::ScheduledVod.new() }
    context "on languages" do

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

        it 'should allow lowercase languages values' do
          scheduled_vod.languages = 'na'
        end

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

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

        it 'should allow lowercase comma separated languages values and strings with hyphens' do
          scheduled_vod.languages = 'this,is,valid'
        end

      end

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

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

        it 'should not allow spaces in the languages' do
          scheduled_vod.languages = 'na wewe'
        end

        it 'should not allow uppercase in the begining of the languages' do
          scheduled_vod.languages = 'Na'
        end

        it 'should not allow uppercase in the languages' do
          scheduled_vod.languages = 'aNaa'
        end

        it 'should not allow uppercase in the languages' do
          scheduled_vod.languages = 'aw-aNaa'
        end
      end
    end
  end

  context "duplicate" do
      context 'valid duplicate' do
        let(:scheduled_vod) { Promotions::ScheduledVod.from_attributes(user_id: 2, login: "testlogin", vod_id: "somemd5", title: "title", description_raw: "description", description_rendered:"<p>description\n</p>", priority: 1, image_url: "url", sponsored: false, id: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1', languages: nil, start_date: "2017-09-19T18:00:00Z", end_date: "2017-09-20T18:00:00Z", inserted_at: "2017-01-1T00:00:00Z", updated_at: "2017-01-1T00:00:00Z")}
        let(:dup_scheduled_vod) { Promotions::ScheduledVod.from_attributes(user_id:2, login:"testlogin", priority:1, title:"title", image_url:"url", inserted_at:nil, updated_at:nil, sponsored:false, vod_id:"somemd5", description_raw:"description", description_rendered:"<p>description\n</p>", languages: nil, start_date: "2017-09-19T18:00:00Z", start_date_part:"2017-09-19", start_time_part:"18:00", end_date:"2017-09-20T18:00:00Z", end_date_part:"2017-09-20", end_time_part: "18:00") }

        context 'hypeman success' do
          it 'returns allow dup values' do
            expect(scheduled_vod.duplicate()) == dup_scheduled_vod
          end
        end
      end
  end

  context "#create" do
    let(:invalid_scheduled_vod) { Promotions::ScheduledVod.new }
    let(:scheduled_vod) { Promotions::ScheduledVod.new(vod_id:"somemd5", title: "title", description_raw: "description", priority: 1, image_url: "url", sponsored: false,  languages: "en", login: "test_login", start_date_part: "2017-09-19", start_time_part:"18:00", end_date_part:"2017-09-20", end_time_part: "18:00")}
    let(:response) { double 'hypeman response' }

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

    context 'valid creation' do
      let(:expected_url) { '/admin/vods' }
      let(:expected_body) { '{"scheduled_vod":{"user_id":null,"login":"test_login","priority":1,"title":"title","image_url":"url","inserted_at":null,"updated_at":null,"sponsored":false,"vod_id":"somemd5","description_raw":"description","languages":["en"],"start_date":"2017-09-19 18:00:00Z","end_date":"2017-09-20 18:00:00Z"}}' }
      let(:expected_headers) { { 'Content-Type' => 'application/json' } }

      before do
        expect(Promotions::ScheduledVod).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({"scheduled_vod" => {
            "vod_id" => "somemd5", "user_id" => 96353013, "title" => "title",
            "start_date" => "2017-09-19 18:00:00+00:00", "sponsored" => false, "priority" => 1,
            "login" => "test_login", "languages" => ["en"], "image_url" => "google.com",
            "id" => "aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1", "end_date" => "2017-09-20 18:00:00+00:00",
            "description_rendered" => "<p>description</p>\n", "description_raw" => "description"}}).at_least(1)
          expect(response).to receive(:success?).and_return(true).at_least(1)
        end
        it 'submits allowed values to endpoint' do
          expect(scheduled_vod.save()).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(scheduled_vod.save()).to eq(false)
          expect(scheduled_vod.errors[:base]).to eq(['Create failed in Hypeman'])
        end
      end

    end
  end

  context "#update" do
    let(:scheduled_vod) { Promotions::ScheduledVod.from_attributes(vod_id: "somemd5", title: "title", description_raw: "description", priority: 1, image_url: "url", sponsored: false, id: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1', languages: "", start_date: "2017-09-19T18:00:00Z", end_date: "2017-09-20T18:00:00Z", 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(scheduled_vod.update(changes)).to eq(false)
    end

    context 'valid updates' do
      let(:changes) { { priority: 10, sponsored: true, title: 'New title', languages: 'en' } }
      let(:expected_url) { '/admin/vods/aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1' }
      let(:expected_body) { '{"scheduled_vod":{"priority":10,"title":"New title","image_url":"url","sponsored":true,"vod_id":"somemd5","description_raw":"description","languages":["en"],"start_date":"2017-09-19 18:00:00Z","end_date":"2017-09-20 18:00:00Z"}}'}
      let(:expected_headers) { { 'Content-Type' => 'application/json' } }

      before do
        expect(Promotions::ScheduledVod).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(scheduled_vod.update(changes)).to eq(true)
        end

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

          expect(scheduled_vod.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},
             "languages" => {old_value: "", new_value: ["en"]}
          })
        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(scheduled_vod.update(changes)).to eq(false)
          expect(scheduled_vod.errors[:base]).to eq(['Update failed in Hypeman'])
        end
      end
    end
  end

  context "destroy" do
    let(:scheduled_vod) { Promotions::ScheduledVod.from_attributes(title: "title", description_raw: "description", priority: 1, image_url: "url", sponsored: false, id: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1', languages: "")}
    let(:connection) { double }
    let(:response) { double }

    context 'valid deletion' do
      let(:expected_url) { '/admin/vods/aaaaaaaa-aaaa-aaaa-aaaa-aaaabbbbccc1' }
      before do
        expect(Promotions::ScheduledVod).to receive(:delete).with(expected_url).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(scheduled_vod.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(scheduled_vod.destroy()).to eq(false)
          expect(scheduled_vod.errors[:base]).to eq(['Delete failed in Hypeman'])
        end
      end

    end
  end
end
