module Imap::Backup
  describe Setup::FolderChooser do
    include HighLineTestHelpers

    describe "#run" do
      subject { described_class.new(account) }

      let(:connection) do
        instance_double(
          Account::Connection, folder_names: connection_folders
        )
      end
      let(:account) do
        instance_double(
          Account,
          folders: account_folders,
          "folders=": nil
        )
      end
      let(:account_folders) { [] }
      let(:connection_folders) { [] }
      let!(:highline_streams) { prepare_highline }
      let(:input) { highline_streams[0] }
      let(:output) { highline_streams[1] }

      before do
        allow(Account::Connection).to receive(:new) { connection }
        allow(Kernel).to receive(:system)
        allow(Logger.logger).to receive(:warn)
      end

      describe "display" do
        it "clears the screen" do
          expect(Kernel).to receive(:system).with("clear")

          subject.run
        end

        it "shows the menu" do
          subject.run

          expect(output.string).to match %r{Add/remove folders}
        end
      end

      describe "folder listing" do
        let(:account_folders) { [{name: "my_folder"}] }
        let(:connection_folders) do
          # N.B. my_folder is already backed up
          %w(my_folder another_folder)
        end

        describe "display" do
          before { subject.run }

          it "shows folders which are being backed up" do
            expect(output.string).to include("+ my_folder")
          end

          it "shows folders which are not being backed up" do
            expect(output.string).to include("- another_folder")
          end
        end

        context "when adding folders" do
          before do
            allow(input).to receive(:gets).and_return("2\n", "q\n")

            subject.run
          end

          specify "are added to the account" do
            expect(account).to have_received(:"folders=").
              with([{name: "my_folder"}, {name: "another_folder"}])
          end
        end

        context "when removing folders" do
          before do
            allow(input).to receive(:gets).and_return("1\n", "q\n")

            subject.run
          end

          specify "are removed from the account" do
            expect(account).to have_received(:"folders=").with([])
          end
        end
      end

      context "with missing remote folders" do
        let(:account_folders) do
          [{name: "on_server"}, {name: "not_on_server"}]
        end
        let(:connection_folders) { ["on_server"] }

        before do
          allow(Kernel).to receive(:puts)
          subject.run
        end

        specify "are removed from the account" do
          expect(account).to have_received(:"folders=").
            with([{name: "on_server"}])
        end
      end

      context "when folders are not available" do
        let(:connection_folders) { nil }

        before do
          allow(Setup.highline).
            to receive(:ask) { "q" }
        end

        it "asks to press a key" do
          expect(Setup.highline).
            to receive(:ask).with("Press a key ")

          subject.run
        end
      end

      context "with connection errors" do
        before do
          allow(Account::Connection).
            to receive(:new).with(account).and_raise("error")
          allow(Setup.highline).
            to receive(:ask) { "q" }
        end

        it "prints an error message" do
          expect(Logger.logger).
            to receive(:warn).with("Connection failed")

          subject.run
        end

        it "asks to continue" do
          expect(Setup.highline).
            to receive(:ask).with("Press a key ")

          subject.run
        end
      end
    end
  end
end
