# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Git::Commands::Clean do
  let(:execution_context) { execution_context_double }
  let(:command) { described_class.new(execution_context) }

  describe '#call' do
    context 'with no arguments' do
      it 'runs git clean without any flags' do
        expected_result = command_result
        expect_command_capturing('clean').and_return(expected_result)

        result = command.call

        expect(result).to eq(expected_result)
      end
    end

    context 'with the :force argument' do
      it 'adds --force to the command line' do
        expect_command_capturing('clean', '--force').and_return(command_result)

        command.call(force: true)
      end
    end

    context 'with force: 2' do
      it 'emits --force twice' do
        expect_command_capturing('clean', '--force', '--force').and_return(command_result)
        command.call(force: 2)
      end

      it 'accepts :f as an alias' do
        expect_command_capturing('clean', '--force').and_return(command_result)

        command.call(f: true)
      end
    end

    context 'with the :d argument' do
      it 'adds -d to the command line' do
        expect_command_capturing('clean', '-d').and_return(command_result)

        command.call(d: true)
      end
    end

    context 'with the :dry_run option' do
      it 'adds --dry-run to the command line' do
        expect_command_capturing('clean', '--dry-run').and_return(command_result)

        command.call(dry_run: true)
      end

      it 'accepts :n as an alias' do
        expect_command_capturing('clean', '--dry-run').and_return(command_result)

        command.call(n: true)
      end
    end

    context 'with the :quiet option' do
      it 'adds --quiet to the command line' do
        expect_command_capturing('clean', '--quiet').and_return(command_result)

        command.call(quiet: true)
      end

      it 'accepts :q as an alias' do
        expect_command_capturing('clean', '--quiet').and_return(command_result)

        command.call(q: true)
      end
    end

    context 'with the :chdir execution option' do
      it 'passes chdir to the execution context, not to the git CLI' do
        expect_command_capturing('clean', chdir: '/some/dir').and_return(command_result)

        command.call(chdir: '/some/dir')
      end
    end

    context 'with the :exclude option' do
      it 'adds --exclude=<pattern> to the command line' do
        expect_command_capturing('clean', '--exclude=*.log').and_return(command_result)

        command.call(exclude: '*.log')
      end

      it 'repeats --exclude= for each pattern when given an array' do
        expect_command_capturing('clean', '--exclude=*.log', '--exclude=tmp/').and_return(command_result)

        command.call(exclude: %w[*.log tmp/])
      end

      it 'accepts :e as an alias' do
        expect_command_capturing('clean', '--exclude=*.log').and_return(command_result)

        command.call(e: '*.log')
      end
    end

    context 'with the :x argument' do
      it 'adds -x to the command line' do
        expect_command_capturing('clean', '-x').and_return(command_result)

        command.call(x: true)
      end
    end

    context 'with the :X option' do
      it 'adds -X to the command line' do
        expect_command_capturing('clean', '-X').and_return(command_result)

        command.call(X: true)
      end
    end

    context 'with the :pathspec option' do
      it 'appends pathspec after -- separator' do
        expect_command_capturing('clean', '--', 'tmp/').and_return(command_result)

        command.call(pathspec: 'tmp/')
      end

      it 'appends multiple pathspecs after -- separator' do
        expect_command_capturing('clean', '--', 'tmp/', 'build/').and_return(command_result)

        command.call(pathspec: %w[tmp/ build/])
      end

      it 'combines pathspec with other options' do
        expect_command_capturing('clean', '--force', '--', 'tmp/').and_return(command_result)

        command.call(force: true, pathspec: 'tmp/')
      end
    end

    context 'with multiple options combined' do
      it 'includes all specified flags' do
        expect_command_capturing('clean', '-d', '--force', '-x').and_return(command_result)
        command.call(force: true, d: true, x: true)
      end
    end

    context 'input validation' do
      it 'raises an ArgumentError for unexpected options' do
        expect { command.call(unexpected: true) }.to(
          raise_error(ArgumentError, /Unsupported options: :unexpected/)
        )
      end

      it 'raises an ArgumentError for unexpected positional arguments' do
        expect { command.call('unexpected') }.to(
          raise_error(ArgumentError, /Unexpected positional arguments: unexpected/)
        )
      end
    end
  end
end
