RSpec.describe ERDL::Executable do
  subject { ERDL::FileUtilities.new(opts, 'ftp', location: 'test_dir') }

  describe '#stream_to_ftp?' do
    let(:opts) { { dry_run: false, alert: true } }

    it 'it opens then closes an ftp connection' do
      allow(subject).to receive(:filename_from_url).and_return('test_filename')
      ftp = instance_double(Net::FTP).as_null_object # don't care about unexpected messages
      allow(ftp).to receive_message_chain(:nlst, :last) # or fails with "Net::FTP does not implement: last"

      expect(ftp).to receive(:login)
      expect(ftp).to receive(:chdir)
      expect(subject).to receive(:remote_file_exists?)
      expect(ftp).to receive(:putbinaryfile)
      expect(ftp).to receive(:close)
      expect(subject).to receive(:open)
      expect { subject.stream_to_ftp?('http://url.com', ftp) }.to_not raise_error
    end
  end

  describe '#stream_to_sftp?' do
    let(:opts) { { dry_run: false, alert: true } }

    it 'it opens then closes an sftp connection' do
      allow(subject).to receive(:filename_from_url).and_return('test_filename')
      conn_info = ['test.com', 'user', { password: 'password' }]
      sftp = double.as_null_object
      allow(Net::SFTP).to receive(:start).with(*conn_info)
        .and_yield(sftp)
      expect(sftp).to receive(:upload!)
      expect(subject).to receive(:remote_file_exists?)
      expect(sftp).to receive(:close_channel)
      expect(subject).to receive(:open)
      expect { subject.stream_to_sftp?('http://url.com', sftp) }.to_not raise_error
    end
  end

  describe '#stream_to_s3?' do
    let(:opts) { { dry_run: false, alert: true } }

    it 'it creates an S3 resource' do
      allow(subject).to receive(:filename_from_url).and_return('test_filename')
      s3 = instance_double(Aws::S3::Resource).as_null_object
      bucket = instance_double(Aws::S3::Bucket).as_null_object

      expect(s3).to receive(:bucket).and_return(bucket)
      expect(subject).to receive(:remote_file_exists?)
      expect(bucket).to receive(:put_object)
      expect(subject).to receive(:open)
      expect { subject.stream_to_s3?('http://url.com', s3) }.to_not raise_error
    end
  end

  describe '#remote_file_exists?' do
    let(:filename) { 'test_file' }
    let(:remote_files) { instance_double(Array) }

    context 'ftp' do
      let(:subcommand) { 'ftp' }
      let(:remote) { instance_double(Net::FTP).as_null_object }
      it 'it checks filenames on the ftp server' do
        allow(remote).to receive(:nlst).and_return(remote_files)
      end
    end

    context 's3' do
      let(:subcommand) { 's3' }
      let(:remote) { instance_double(Aws::S3::Bucket).as_null_object }
      let(:directory) { 'test_directory' }
      it 'it checks filenames on the S3 server' do
        allow(remote).to receive(:objects).and_return(remote_files)
      end
    end
  end
  describe '#filename_from_url' do
    let(:opts) { { dry_run: false, alert: true } }
    it 'returns filename from url including .gz' do
      expect(subject.filename_from_url(
               'https://storage.googleapis.com/ytf-reports-archive/4756695779/' \
               'YouTube_theorchardmusic_M_20200101_20200131_rawdata_v1-0.csv.gz?GoogleAccessId='))
        .to eq('YouTube_theorchardmusic_M_20200101_20200131_rawdata_v1-0.csv.gz')
    end
    it 'returns filename from url when filename ends in .csv' do
    expect(subject.filename_from_url(
        'https://storage.googleapis.com/ytf-reports-archive/4756695779/' \
               'YouTube_theorchardmusic_W_20200101_20200131_rawdata_v1-0.csv?GoogleAccessId='))
        .to eq('YouTube_theorchardmusic_W_20200101_20200131_rawdata_v1-0.csv')
    end
    it 'returns filename from url when filename ends in .zip' do
      expect(subject.filename_from_url(
          'https://storage.googleapis.com/ytf-reports-archive/4756695779/' \
               'YouTube_theorchardmusic_W_20200101_20200131_rawdata_v1-0.csv.zip?GoogleAccessId='))
          .to eq('YouTube_theorchardmusic_W_20200101_20200131_rawdata_v1-0.csv.zip')
    end
    it 'errors on bad url' do
      expect { subject.filename_from_url("bad_url") }.to raise_error
    end

  end
end
