require_relative "shell_helpers"

module Omnibus
  module RSpec
    module GitHelpers
      include ShellHelpers

      def git_origin_for(repo, options = {})
        "file://#{fake_git_remote("git://github.com/omnibus/#{repo}.git", options)}/.git"
      end

      def local_git_repo(name, options = {})
        path = git_scratch
        Dir.chdir(path) do
          # Create a bogus configure file
          File.open("configure", "w") { |f| f.write('echo "Done!"') }

          git %{init .}
          git %{add .}
          git %{commit -am "Initial commit for #{name}..."}
          git %{remote add origin "#{options[:remote]}"} if options[:remote]
          git %{push origin master}

          if options[:annotated_tags]
            options[:annotated_tags].each do |tag|
              File.open("tag", "w") { |f| f.write(tag) }
              git %{add tag}
              git %{commit -am "Create tag #{tag}"}
              git %{tag "#{tag}" -m "#{tag}"}
              git %{push origin "#{tag}"} if options[:remote]
            end
          end

          if options[:tags]
            options[:tags].each do |tag|
              File.open("tag", "w") { |f| f.write(tag) }
              git %{add tag}
              git %{commit -am "Create tag #{tag}"}
              git %{tag "#{tag}"}
              git %{push origin "#{tag}"} if options[:remote]
            end
          end

          if options[:branches]
            options[:branches].each do |branch|
              git %{checkout -b #{branch} master}
              File.open("branch", "w") { |f| f.write(branch) }
              git %{add branch}
              git %{commit -am "Create branch #{branch}"}
              git %{push origin "#{branch}"} if options[:remote]
              git %{checkout master}
            end
          end
        end
        path
      end

      def remote_git_repo(name, options = {})
        path = File.join(remotes, name)
        remote_url = "file://#{path}"
        options[:remote] = remote_url
        # Create a bogus software
        FileUtils.mkdir_p(path)

        Dir.chdir(path) do
          git %{init --bare}
          git %{config core.sharedrepository 1}
          git %{config receive.denyNonFastforwards true}
          git %{config receive.denyCurrentBranch ignore}
        end

        local_git_repo(name, options)
        path
      end

      # Calculate the git sha for the given ref.
      #
      # @param [#to_s] repo
      #   the repository to show the ref for
      # @param [#to_s] ref
      #   the ref to show
      #
      # @return [String]
      def sha_for_ref(repo, ref)
        Dir.chdir(File.join(remotes, repo)) do
          git("show-ref #{ref}").stdout.split(/\s/).first
        end
      end

      private

      # The path to store the git remotes.
      #
      # @return [Pathname]
      def remotes
        path = File.join(tmp_path, "git", "remotes")
        FileUtils.mkdir_p(path) unless File.directory?(path)
        path
      end

      def git_scratch
        path = File.join(tmp_path, "git", "scratch")
        FileUtils.mkdir_p(path) unless File.directory?(path)
        path
      end

      def git(command)
        #
        # We need to override some of the variable's git uses for generating
        # the SHASUM for testing purposes
        #
        time = Time.at(680227200).utc.strftime("%c %z")
        env  = {
          "GIT_AUTHOR_NAME" => "omnibus",
          "GIT_AUTHOR_EMAIL" => "omnibus@getchef.com",
          "GIT_AUTHOR_DATE" => time,
          "GIT_COMMITTER_NAME" => "omnibus",
          "GIT_COMMITTER_EMAIL" => "omnibus@gechef.com",
          "GIT_COMMITTER_DATE" => time,
        }

        shellout!("git #{command}", env: env)
      end
    end
  end
end
