# frozen_string_literal: true

require 'spec_helper'
require 'git/commands/checkout/files'

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

  describe '#call' do
    context 'with nil tree_ish (restore from index)' do
      it 'omits tree_ish from command when nil' do
        expected_result = command_result
        expect_command_capturing('checkout', '--', 'file.txt').and_return(expected_result)

        result = command.call(pathspec: ['file.txt'])

        expect(result).to eq(expected_result)
      end

      it 'restores multiple files from index' do
        expect_command_capturing('checkout', '--', 'file1.txt', 'file2.txt').and_return(command_result)
        command.call(pathspec: ['file1.txt', 'file2.txt'])
      end

      it 'works with options' do
        expect_command_capturing('checkout', '--force', '--', 'file.txt').and_return(command_result)
        command.call(pathspec: ['file.txt'], force: true)
      end
    end

    context 'with tree_ish and pathspec' do
      it 'places tree_ish before -- separator' do
        expect_command_capturing('checkout', 'HEAD~1', '--', 'file.txt').and_return(command_result)
        command.call('HEAD~1', pathspec: ['file.txt'])
      end

      it 'accepts branch name as tree_ish' do
        expect_command_capturing('checkout', 'main', '--', 'file.txt').and_return(command_result)
        command.call('main', pathspec: ['file.txt'])
      end

      it 'accepts commit SHA as tree_ish' do
        expect_command_capturing('checkout', 'abc123', '--', 'file.txt', 'other.txt').and_return(command_result)
        command.call('abc123', pathspec: %w[file.txt other.txt])
      end

      it 'accepts tag as tree_ish' do
        expect_command_capturing('checkout', 'v1.0.0', '--', 'config.yml').and_return(command_result)
        command.call('v1.0.0', pathspec: ['config.yml'])
      end

      it 'accepts glob patterns' do
        expect_command_capturing('checkout', 'HEAD', '--', '*.rb').and_return(command_result)
        command.call('HEAD', pathspec: ['*.rb'])
      end

      it 'accepts directory paths' do
        expect_command_capturing('checkout', 'HEAD', '--', 'src/').and_return(command_result)
        command.call('HEAD', pathspec: ['src/'])
      end
    end

    context 'with :force option' do
      it 'adds --force flag' do
        expect_command_capturing('checkout', '--force', 'HEAD', '--', 'file.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['file.txt'], force: true)
      end

      it 'works with :f alias' do
        expect_command_capturing('checkout', '--force', 'HEAD', '--', 'file.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['file.txt'], f: true)
      end
    end

    context 'with :ours option (for merge conflicts)' do
      it 'adds --ours flag' do
        expect_command_capturing('checkout', '--ours', 'HEAD', '--', 'conflicted.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['conflicted.txt'], ours: true)
      end
    end

    context 'with :theirs option (for merge conflicts)' do
      it 'adds --theirs flag' do
        expect_command_capturing('checkout', '--theirs', 'HEAD', '--', 'conflicted.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['conflicted.txt'], theirs: true)
      end
    end

    context 'with :merge option (recreate conflict markers)' do
      it 'adds --merge flag' do
        expect_command_capturing('checkout', '--merge', 'HEAD', '--', 'conflicted.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['conflicted.txt'], merge: true)
      end

      it 'works with :m alias' do
        expect_command_capturing('checkout', '--merge', 'HEAD', '--', 'conflicted.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['conflicted.txt'], m: true)
      end
    end

    context 'with :conflict option' do
      it 'adds --conflict=<value> flag' do
        expect_command_capturing('checkout', '--conflict=merge', 'HEAD', '--', 'file.txt').and_return(command_result)
        command.call('HEAD', pathspec: ['file.txt'], conflict: 'merge')
      end
    end

    context 'with :overlay option' do
      context 'when true' do
        it 'adds --overlay flag' do
          expect_command_capturing('checkout', '--overlay', 'main', '--', 'file.txt').and_return(command_result)
          command.call('main', pathspec: ['file.txt'], overlay: true)
        end
      end

      context 'when :no_overlay is true' do
        it 'adds --no-overlay flag' do
          expect_command_capturing('checkout', '--no-overlay', 'main', '--', 'file.txt').and_return(command_result)
          command.call('main', pathspec: ['file.txt'], no_overlay: true)
        end
      end
    end

    context 'with :pathspec_from_file option' do
      it 'adds --pathspec-from-file flag' do
        expect_command_capturing('checkout', '--pathspec-from-file=paths.txt', 'main').and_return(command_result)
        command.call('main', pathspec_from_file: 'paths.txt')
      end

      it 'accepts stdin with -' do
        expect_command_capturing('checkout', '--pathspec-from-file=-', 'HEAD').and_return(command_result)
        command.call('HEAD', pathspec_from_file: '-')
      end
    end

    context 'with :pathspec_file_nul option' do
      it 'adds --pathspec-file-nul flag with pathspec_from_file' do
        expect_command_capturing('checkout', '--pathspec-from-file=paths.txt', '--pathspec-file-nul',
                                 'main').and_return(command_result)
        command.call('main', pathspec_from_file: 'paths.txt', pathspec_file_nul: true)
      end
    end

    context 'with :ignore_skip_worktree_bits option' do
      it 'adds --ignore-skip-worktree-bits flag' do
        expect_command_capturing('checkout', '--ignore-skip-worktree-bits', '--', 'file.txt').and_return(command_result)
        command.call(pathspec: ['file.txt'], ignore_skip_worktree_bits: true)
      end
    end

    context 'with :chdir execution option' do
      it 'passes chdir to the execution context, not to the git CLI' do
        expect_command_capturing('checkout', '--', 'file.txt', chdir: '/some/dir').and_return(command_result)
        command.call(pathspec: ['file.txt'], chdir: '/some/dir')
      end
    end

    context 'with multiple options combined' do
      it 'includes all specified flags in correct order' do
        expect_command_capturing('checkout',
                                 '--force',
                                 '--ours',
                                 'HEAD',
                                 '--',
                                 'file1.txt',
                                 'file2.txt').and_return(command_result)
        command.call('HEAD', pathspec: %w[file1.txt file2.txt], force: true, ours: true)
      end

      it 'combines tree_ish with conflict resolution' do
        expect_command_capturing('checkout',
                                 '--conflict=diff3',
                                 'main',
                                 '--',
                                 'conflicted.txt').and_return(command_result)
        command.call('main', pathspec: ['conflicted.txt'], conflict: 'diff3')
      end
    end
  end
end
