# frozen_string_literal: true

require 'spec_helper'

describe ReleaseTools::Slack::Bookmark do
  let(:slack_channel) { 'foo' }

  shared_examples 'without credentials' do
    it 'raises NoCredentialsError' do
      ClimateControl.modify(SLACK_APP_BOT_TOKEN: nil) do
        expect do
          subject
        end.to raise_error(described_class::NoCredentialsError)
      end
    end
  end

  describe '.list' do
    subject(:list) { described_class.list(channel: slack_channel) }

    it_behaves_like 'without credentials'
    context 'with credentials' do
      let(:fake_client) { double(:client) }
      let(:request_params) { { channel_id: slack_channel } }

      let(:json_response) do
        {
          ok: true,
          channel: slack_channel,
          ts: '123456'
        }.to_json
      end

      let(:response) do
        instance_spy(
          HTTP::Response,
          status: double(:status, success?: true),
          code: 200,
          reason: 'OK',
          body: json_response
        )
      end

      before do
        allow(described_class)
          .to receive(:client).and_return(fake_client)

        allow(fake_client)
          .to receive(:post).and_return(response)
      end

      it 'fetches the list of bookmarks for a slack channel' do
        expect(fake_client)
          .to receive(:post)
          .with(
            described_class::LIST_URL,
            json: request_params
          )

        ClimateControl.modify(SLACK_APP_BOT_TOKEN: '123456') do
          without_dry_run do
            list
          end
        end
      end
    end
  end

  describe '.edit' do
    let(:message) { 'baz' }
    let(:bookmark_id) { 'asdf1234' }
    let(:link) { 'https://example.com' }

    subject(:edit) { described_class.edit(channel: slack_channel, bookmark: bookmark_id, link: link) }

    it_behaves_like 'without credentials'

    context 'with credentials' do
      let(:fake_client) { double(:client) }

      let(:request_params) do
        {
          channel_id: slack_channel,
          bookmark_id: bookmark_id,
          link: link
        }
      end

      let(:json_response) do
        {
          ok: true,
          channel: slack_channel,
          ts: '123456'
        }.to_json
      end

      let(:response) do
        instance_spy(
          HTTP::Response,
          status: double(:status, success?: true),
          code: 200,
          reason: 'OK',
          body: json_response
        )
      end

      before do
        allow(described_class)
          .to receive(:client).and_return(fake_client)

        allow(fake_client)
          .to receive(:post).and_return(response)
      end

      it 'edits a bookmark' do
        expect(fake_client)
          .to receive(:post)
          .with(
            described_class::EDIT_URL,
            json: request_params
          )

        ClimateControl.modify(SLACK_APP_BOT_TOKEN: '123456') do
          without_dry_run do
            edit
          end
        end
      end

      context 'when slack_down FF is on' do
        before do
          enable_feature(:slack_down)
        end

        it 'does not call API' do
          expect(fake_client).not_to receive(:post)

          ClimateControl.modify(SLACK_APP_BOT_TOKEN: '123456') do
            without_dry_run do
              expect(edit).to eq({})
            end
          end
        end
      end

      context 'when response is not ok' do
        let(:json_response) { { ok: false, error: 'invalid_auth' }.to_json }

        around do |ex|
          ClimateControl.modify(SLACK_APP_BOT_TOKEN: '123456') do
            without_dry_run do
              ex.run
            end
          end
        end

        it 'raises SlackBookmarkError' do
          expect { edit }
            .to raise_error(described_class::SlackBookmarkError)
        end
      end

      context 'when response is not successful' do
        let(:response) do
          instance_spy(
            HTTP::Response,
            status: double(:status, success?: false),
            code: 400,
            reason: 'Bad Request',
            body: nil
          )
        end

        around do |ex|
          ClimateControl.modify(SLACK_APP_BOT_TOKEN: '123456') do
            without_dry_run do
              ex.run
            end
          end
        end

        it 'raises SlackBookmarkError' do
          expect { edit }.to raise_error(described_class::SlackBookmarkError)
        end
      end

      context 'with dry run' do
        it 'does nothing' do
          expect(described_class).not_to receive(:client)

          ClimateControl.modify(SLACK_APP_BOT_TOKEN: '123456') do
            expect(edit).to eq({})
          end
        end
      end
    end
  end
end
