require_relative '../retrospective'
require 'timecop'

describe RetrospectiveCommand do
  let(:read_token) { 'read-token' }
  let(:write_token) { 'write-token' }
  let(:options) do
    {
      '--read-token' => read_token,
      '--write-token' => write_token,
      '--dry-run' => false,
      '--force' => false,
      '--all-teams' => false,
      '--team' => 'TeamA',
      'create' => false,
      'update' => false
    }
  end

  let(:read_client) { instance_double(GitlabApi) }
  let(:write_client) { instance_double(GitlabApi) }
  let(:retrospective) { instance_double(Retrospective) }

  subject(:command) { described_class.new }

  before do
    allow(Docopt).to receive(:docopt).and_return(options)
    allow(GitlabApi).to receive(:new).with(token: read_token).and_return(read_client)
    allow(GitlabApi).to receive(:new).with(token: write_token).and_return(write_client)
    allow(Retrospective).to receive(:new).with(read_client: read_client, write_client: write_client).and_return(retrospective)
  end

  describe "#run_for_all_teams" do
    let(:team_a) { instance_double(Team::TeamInfo, name: 'TeamA') }
    let(:team_b) { instance_double(Team::TeamInfo, name: 'TeamB') }
    let(:teams) { [team_a, team_b] }

    before do
      allow(Team).to receive(:all).and_return(teams)
      # Allow puts to prevent test output pollution
      allow(command).to receive(:puts)
    end

    context "with error" do
      before do
        allow(command).to receive(:run_for_team).with(team_a).and_raise(StandardError)
        allow(command).to receive(:run_for_team).with(team_b).and_return(0)
      end

      it 'returns a 1 exit code' do
        expect(command.send(:run_for_all_teams)).to eq(1)
      end
    end

    context "with no errors" do
      before do
        allow(command).to receive(:run_for_team).with(team_a).and_return(0)
        allow(command).to receive(:run_for_team).with(team_b).and_return(0)
      end

      it 'returns a 0 exit code' do
        expect(command.send(:run_for_all_teams)).to eq(0)
      end
    end
  end

  describe "#correct_date?" do
    let(:milestone) do
      {
        'start_date' => '2023-08-18',
        'due_date' => '2023-09-17',
        'title' => '16.4'
      }
    end

    before { Timecop.freeze(current_time) }
    after { Timecop.return }

    context 'when action is create' do
      context 'when it is 9 days since the start of the milestone' do
        let(:current_time) { Date.parse('2023-08-27') }

        it 'is expected to be true' do
          expect(command.send(:correct_date?, 'create', milestone)).to be true
        end
      end

      context 'when it is any date other than 9 days since the start of milestone' do
        let(:current_time) { Date.parse('2023-08-26') }

        it 'is expected to be false' do
          expect(command.send(:correct_date?, 'create', milestone)).to be false
        end
      end
    end

    context 'when action is update' do
      context 'when it is 4 days since the end of the last milestone' do
        let(:current_time) { Date.parse('2023-09-21') }

        it 'is expected to be true' do
          expect(command.send(:correct_date?, 'update', milestone)).to be true
        end
      end

      context 'when it is any date other than 4 days since the end of the last milestone' do
        let(:current_time) { Date.parse('2023-09-22') }

        it 'is expected to be false' do
          expect(command.send(:correct_date?, 'update', milestone)).to be false
        end
      end
    end
  end
end
