require 'rails_helper'
require 'rake'
require 'open3'

RSpec.describe 'nico:export' do
  let(:task) { Rake::Task['nico:export'] }
  let(:success_status) { instance_double(Process::Status, success?: true) }
  let(:failure_status) { instance_double(Process::Status, success?: false) }

  def create_post(url)
    Post.create!(url:)
  end

  before(:all) do
    Rails.application.load_tasks unless Rake::Task.task_defined?('nico:export')
  end

  before do
    task.reenable

    allow(ENV).to receive(:fetch).with('MYSQL_USER').and_return('mysql-user')
    allow(ENV).to receive(:fetch).with('MYSQL_PASS').and_return('mysql-pass')
    allow(ENV).to receive(:fetch).with('NIZIKA_NICO_PATH').and_return('/srv/nizika-nico')
  end

  describe 'export' do
    it 'exports nicovideo ids to shared nico DB' do
      create_post('https://www.nicovideo.jp/watch/sm12345?ref=foo')
      create_post('https://www.nicovideo.jp/watch/so67890#comments')
      create_post('https://www.nicovideo.jp/watch/nm24680')
      create_post('https://example.com/watch/sm99999')

      expect(Open3).to receive(:capture3) do |env, *args, **kwargs|
        expect(env).to eq(
          {
            'MYSQL_USER' => 'mysql-user',
            'MYSQL_PASS' => 'mysql-pass',
          },
        )

        expect(args.take(3)).to eq(
          [
            'python3',
            '-m',
            'tracked_videos.put_bulk_upsert',
          ],
        )

        expect(args.drop(3)).to contain_exactly(
          'sm12345',
          'so67890',
          'nm24680',
        )

        expect(kwargs).to eq(chdir: '/srv/nizika-nico')

        ['', '', success_status]
      end

      task.invoke
    end

    it 'deduplicates video ids' do
      create_post('https://www.nicovideo.jp/watch/sm12345')
      create_post('https://sp.nicovideo.jp/watch/sm12345')

      expect(Open3).to receive(:capture3) do |_env, *args, **_kwargs|
        expect(args.drop(3)).to eq(['sm12345'])

        ['', '', success_status]
      end

      task.invoke
    end

    it 'does not call python when there are no nicovideo posts' do
      create_post('https://example.com/watch/sm12345')

      expect(Open3).not_to receive(:capture3)

      task.invoke
    end

    it 'raises stderr when python command fails' do
      create_post('https://www.nicovideo.jp/watch/sm12345')

      allow(Open3).to receive(:capture3).and_return(
        [
          '',
          'bulk upsert failed',
          failure_status,
        ],
      )

      expect {
        task.invoke
      }.to raise_error(RuntimeError, 'bulk upsert failed')
    end
  end
end
