require 'rails_helper'

RSpec.describe Subscriptions::TenuresController do

  include_context 'mocked permissions'

  let(:permission) { 'ticket_products' }

  describe 'preview_tenure' do
    let(:action) { :preview_tenure }
    let(:start_date) { '01/11/19' }
    let(:end_date) { '02/11/19' }
    let(:user_id) { '1' }
    let(:channel_id) { '1' }

    let(:twirp_preview_tenure_response) do
      Subs::PreviewTenureResponse.new(
        owner_id: user_id,
        item_id: channel_id,
        domain: Chronobreak::Tenure::SUB_DOMAIN,
        streak_value: 1,
        tenure_value: 1
      )
    end

    context 'a user with appropriate permissions' do
      include_context 'an authorized user'

      before do
        expect(Chronobreak::Tenure).to receive(:preview_tenure_with_grant).with(
          user_id,
          channel_id,
          start_date,
          end_date
        ).and_return(twirp_preview_tenure_response)
        post action, params: {
          user_id: user_id,
          channel_id: channel_id,
          start: start_date,
          end: end_date
        }
      end

      it 'redirects to tenures index view after preview tenure' do
        expect(response.code).to eq('302')
      end
    end
  end

  describe 'upsert_grant' do
    let(:action) { :upsert_grant }
    let(:start_date) { '01/11/19' }
    let(:end_date) { '02/11/19' }
    let(:user_id) { '1' }
    let(:channel_id) { '1' }

    let(:twirp_upsert_grant_response) do
      data = Subs::UpsertGrantResponse.new
      Twirp::ClientResp.new(data, nil)
    end

    context 'a user with appropriate permissions' do
      include_context 'an authorized user'

      before do
        expect(Chronobreak::Tenure).to receive(:upsert_override_grant).with(
          user_id,
          channel_id,
          start_date,
          end_date
        ).and_return(twirp_upsert_grant_response)
        post action, params: {
          user_id: user_id,
          channel_id: channel_id,
          start: start_date,
          end: end_date
        }
      end

      it 'redirects to new tenure index view after upserting grant' do
        expect(response.code).to eq('302')
      end
    end
  end

  describe 'delete_grant' do
    describe 'permissions' do
      let(:action) { :delete_grant }
      let(:id) { 'subChannel:193:193' }
      let(:origin) { '1234' }
      let(:domain) { Chronobreak::Tenure::SUB_DOMAIN }
      let(:channelID) { '193' }
      let(:userID) { '193' }

      let(:twirp_delete_grants_response) do
        data = Subs::DeleteOverrideGrantResponse.new
        Twirp::ClientResp.new(data, nil)
      end

      context 'a user with appropriate permissions' do
        include_context 'an authorized user'

        before do
          expect(Chronobreak::Tenure).to receive(:delete_override_grant).with(
            userID,
            channelID,
            origin,
            domain
          ).and_return(twirp_delete_grants_response)
          post action, params: {
            id: id,
            origin: origin
          }
        end

        it 'redirects to tenures index view after deleting grant' do
          expect(response.code).to eq('302')
        end
      end
    end
  end

  describe 'index' do
    describe 'permissions' do
      let(:action) { :index }
      let(:channelID) { '1' }
      let(:channelName) { 'name' }
      let(:userID) { '2' }
      let(:userName) { 'anotherName' }

      let(:channel) do
        Twitch::User.new(
          id: channelID,
          login: channelName
        )
      end
      let(:user) do
        Twitch::User.new(
          id: userID,
          login: userName
        )
      end
      let(:grants) do
        [
          {
            id: 'subChannel:122375217:232649790',
            owner_id: '232649790',
            domain: 'subChannel',
            item_id: '122375217',
            origin: 'amzn1.twitch.payments.order.fc911b8d-79f4-4151-8f25-10977faf0ee6',
            action: 'OVERRIDE',
            start: {
              seconds: 1_533_080_726,
              nanos: 0
            },
            end: {
              seconds: 1_535_759_126,
              nanos: 0
            },
            updated_at: {
              seconds: -62_135_596_800,
              nanos: 0
            },
            created_at: {
              seconds: -62_135_596_800,
              nanos: 0
            }
          }
        ]
      end

      let(:twirp_cumulative_response) do
        Subs::ReadTenureResponse.new(
          owner_id: userID,
          item_id: channelID,
          domain: Chronobreak::Tenure::SUB_DOMAIN,
          tenure_value: 2,
          tenure_method: Chronobreak::Tenure::TENURE_METHODS[:CUMULATIVE],
          start: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 1, 1).to_s),
          end: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 2, 1).to_s)
        )
      end
      let(:twirp_streak_response) do
        Subs::ReadTenureResponse.new(
          owner_id: userID,
          item_id: channelID,
          domain: Chronobreak::Tenure::SUB_DOMAIN,
          tenure_value: 2,
          tenure_method: Chronobreak::Tenure::TENURE_METHODS[:STREAK],
          start: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 1, 1).to_s),
          end: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 2, 1).to_s)
        )
      end
      let(:twirp_badges_response) do
        Substwirp::Badges::GetSubscriberBadgeResponse.new(
          badge_type: 0,
          badge_version: '1m'
        )
      end
      let(:twirp_grants_response) do
        data = Subs::ReadGrantsResponse.new grants: grants
        Twirp::ClientResp.new(data, nil)
      end
      let(:twirp_multiple_cumulative_response) do
        Subs::ReadTenuresResponse.new(
          tenures: [{
            owner_id: userID,
            item_id: channelID,
            domain: Chronobreak::Tenure::SUB_DOMAIN,
            value: 2,
            method: Chronobreak::Tenure::TENURE_METHODS[:CUMULATIVE],
            start: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 1, 1).to_s),
            end: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 2, 1).to_s)
          }]
        )
      end
      let(:twirp_multiple_streak_response) do
        Subs::ReadTenuresResponse.new(
          tenures: [{
            owner_id: userID,
            item_id: channelID,
            domain: Chronobreak::Tenure::SUB_DOMAIN,
            value: 2,
            method: Chronobreak::Tenure::TENURE_METHODS[:STREAK],
            start: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 1, 1).to_s),
            end: Chronobreak::Tenure.time_to_protobuf_timestamp(Time.new(2019, 2, 1).to_s)
          }]
        )
      end

      context 'a user with appropriate permissions' do
        include_context 'an authorized user'

        context 'loads the index' do
          before do
            get action
          end

          it_behaves_like 'it returns a success response'
        end

        context "performs a non-successful lookup" do

          context 'with nil params' do

            before do
              get action, params: {
                tenure: {
                  channelID: nil,
                  channelName: nil,
                  userID: nil,
                  userName: nil
                }
              }
            end

            it 'redirects to tenures index view when no arguments are passed' do
              expect(response.code).to eq('302')
            end
          end

          context 'with missing userID and missing channelID' do

            before do
              expect(Twitch::User).to receive(:find).with(channelID).and_return(nil)
              expect(Twitch::User).to receive(:find).with(userID).and_return(nil)
              get action, params: {
                tenure: {
                  channelID: channelID,
                  channelName: nil,
                  userID: userID,
                  userName: nil
                }
              }
            end

            it 'redirects to tenures index view when a channel/user cannot be found' do
              expect(response.code).to eq('302')
            end
          end

          context 'with found channelID and missing userID' do

            before do
              expect(Twitch::User).to receive(:find).with(channelID).and_return(channel)
              expect(Twitch::User).to receive(:find).with(userID).and_return(nil)
              get action, params: {
                tenure: {
                  channelID: channelID,
                  channelName: nil,
                  userID: userID,
                  userName: nil
                }
              }
            end

            it 'redirects to tenures index view when a channel/user cannot be found' do
              expect(response.code).to eq('302')
            end
          end

          context 'with found userID and missing channelID' do

            before do
              expect(Twitch::User).to receive(:find).with(channelID).and_return(nil)
              expect(Twitch::User).to receive(:find).with(userID).and_return(user)
              get action, params: {
                tenure: {
                  channelID: channelID,
                  channelName: nil,
                  userID: userID,
                  userName: nil
                }
              }
            end

            it 'redirects to tenures index view when a channel/user cannot be found' do
              expect(response.code).to eq('302')
            end
          end

          context 'with missing channelName and missing userName' do

            before do
              expect(Twitch::User).to receive(:find_by_login).with(channelName).and_return(nil)
              expect(Twitch::User).to receive(:find_by_login).with(userName).and_return(nil)
              get action, params: {
                tenure: {
                  channelID: nil,
                  channelName: channelName,
                  userID: nil,
                  userName: userName
                }
              }
            end

            it 'redirects to tenures index view when a channel/user cannot be found' do
              expect(response.code).to eq('302')
            end
          end

          context 'with found channelName and missing userName' do

            before do
              expect(Twitch::User).to receive(:find_by_login).with(channelName).and_return(channel)
              expect(Twitch::User).to receive(:find_by_login).with(userName).and_return(nil)
              get action, params: {
                tenure: {
                  channelID: nil,
                  channelName: channelName,
                  userID: nil,
                  userName: userName
                }
              }
            end

            it 'redirects to tenures index view when a channel/user cannot be found' do
              expect(response.code).to eq('302')
            end
          end

          context 'with found userName and missing channelName' do

            before do
              expect(Twitch::User).to receive(:find_by_login).with(channelName).and_return(nil)
              expect(Twitch::User).to receive(:find_by_login).with(userName).and_return(user)
              get action, params: {
                tenure: {
                  channelID: nil,
                  channelName: channelName,
                  userID: nil,
                  userName: userName
                }
              }
            end

            it 'redirects to tenures index view when a channel/user cannot be found' do
              expect(response.code).to eq('302')
            end
          end
        end

        context "performs a successful lookup" do
          include_context 'it creates any tracking call'
          context 'with found userID and channelID, with a tenure response' do

            before do
              expect(Twitch::User).to receive(:find).with(channelID).and_return(channel)
              expect(Twitch::User).to receive(:find).with(userID).and_return(user)
              expect(Chronobreak::Tenure).to receive(:find_tenure).with(
                userID,
                channelID,
                Chronobreak::Tenure::SUB_DOMAIN,
                Chronobreak::Tenure::TENURE_METHODS[:CUMULATIVE]
              ).and_return(twirp_cumulative_response)
              expect(Chronobreak::Tenure).to receive(:find_tenure).with(
                userID,
                channelID,
                Chronobreak::Tenure::SUB_DOMAIN,
                Chronobreak::Tenure::TENURE_METHODS[:STREAK]
              ).and_return(twirp_streak_response)
              expect(Substwirp::Badges).to receive(:get_subscriber_badge).with({
                user_id: userID,
                channel_id: channelID
              }).and_return(twirp_badges_response)
              expect(Subscriptions::Badge).to receive(:existing_and_available_for).with(channel_id: channelID).and_return(nil)
              expect(Chronobreak::Tenure).to receive(:find_grants).with(
                userID,
                channelID,
                Chronobreak::Tenure::SUB_DOMAIN
              ).and_return(twirp_grants_response)
              expect(Chronobreak::Tenure).to receive(:find_tenures).with(
                userID,
                channelID,
                Chronobreak::Tenure::SUB_DOMAIN,
                Chronobreak::Tenure::TENURE_METHODS[:CUMULATIVE]
              ).and_return(twirp_multiple_cumulative_response)
              expect(Chronobreak::Tenure).to receive(:find_tenures).with(
                userID,
                channelID,
                Chronobreak::Tenure::SUB_DOMAIN,
                Chronobreak::Tenure::TENURE_METHODS[:STREAK]
              ).and_return(twirp_multiple_streak_response)

              get action, params: {
                tenure: {
                  channelID: channelID,
                  channelName: nil,
                  userID: userID,
                  userName: nil
                }
              }
            end

            it_behaves_like 'it returns a success response'
          end
        end
      end

      context 'a user without appropriate permissions' do
        include_context 'an unauthorized user'

        before do
          get action
        end

        it_behaves_like 'it redirects the user and displays an error'
      end
    end

  end
end
