require_relative '../util'

class SugarJar
  class Commands
    def smartpullrequest(*args)
      assert_in_repo!
      assert_common_main_branch!

      # does not use `dirty_check!` because we don't allow overriding here
      if dirty?
        SugarJar::Log.warn(
          'Your repo is dirty, so I am not going to create a pull request. ' +
          'You should commit or amend and push it to your remote first.',
        )
        exit(1)
      end

      user_specified_base = args.include?('-B') || args.include?('--base')

      curr = current_branch
      base = tracked_branch
      if @pr_autofill
        SugarJar::Log.info('Autofilling in PR from commit message')
        num_commits = git(
          'rev-list', '--count', curr, "^#{base}"
        ).stdout.strip.to_i
        if num_commits > 1
          args.unshift('--fill-first')
        else
          args.unshift('--fill')
        end
      end
      unless user_specified_base
        if subfeature?(base)
          if upstream_org != push_org
            SugarJar::Log.warn(
              'Unfortunately you cannot based one PR on another PR when' +
              " using fork-based PRs. We will base this on #{most_main}." +
              ' This just means the PR "Changes" tab will show changes for' +
              ' the full stack until those other PRs are merged and this PR' +
              ' PR is rebased.',
            )
          # nil is prompt, true is always, false is never
          elsif @pr_autostack.nil?
            $stdout.print(
              'It looks like this is a subfeature, would you like to base ' +
              "this PR on #{base}? [y/n] ",
            )
            ans = $stdin.gets.strip
            args.unshift('--base', base) if %w{Y y}.include?(ans)
          elsif @pr_autostack
            args.unshift('--base', base)
          end
        elsif base.include?('/') && base != most_main
          # If our base is a remote branch, then use that as the
          # base branch of the PR
          args.unshift('--base', base.split('/').last)
        end
      end

      # <org>:<branch> is the GH API syntax for:
      #   look for a branch of name <branch>, from a fork in owner <org>
      if @repo_forge == 'github'
        # On GitHub, the head is the org and the *BRANCH* name to use as
        # the head branch...
        args.unshift('--head', "#{push_org}:#{curr}")
      else
        # On GitLab, the head is the repo (org/repo) to use as the head
        # _repo_, and then branch is configured seperately (with -s), but
        # we don't need that since it defaults to the local branch name.
        #
        # Then we need --yes for it to not prompt us
        args.unshift('--head', "#{push_org}/#{reponame}", '--yes')
      end

      bin = SugarJar::Util.which(_forge_cmd)
      subcmd = _pr_cmd
      SugarJar::Log.trace(
        "Running: #{bin} #{subcmd} create #{args.join(' ')}",
      )
      system(bin, subcmd, 'create', *args)
    end

    alias spr smartpullrequest
    alias smartpr smartpullrequest

    private

    def _pr_cmd
      @repo_forge == 'gitlab' ? 'mr' : 'pr'
    end

    def assert_common_main_branch!
      upstream_branch = main_remote_branch(upstream)
      unless main_branch == upstream_branch
        die(
          "The local main branch is '#{main_branch}', but the main branch " +
          "of the #{upstream} remote is '#{upstream_branch}'. You probably " +
          "want to rename your local branch by doing:\n\t" +
          "git branch -m #{main_branch} #{upstream_branch}\n\t" +
          "git fetch #{upstream}\n\t" +
          "git branch -u #{upstream}/#{upstream_branch} #{upstream_branch}\n" +
          "\tgit remote set-head #{upstream} -a",
        )
      end
      return if upstream_branch == 'origin'

      origin_branch = main_remote_branch('origin')
      # NOTE: that on GL, forks don't fork any branches by default, even
      # a main one, so if it's 'nil', then ignore.
      return if origin_branch.nil? || origin_branch == upstream_branch

      die(
        "The main branch of your upstream (#{upstream_branch}) and your " +
        "fork/origin (#{origin_branch}) are not the same. You should go " +
        "to https://#{@ghhost || 'github.com'}/#{@ghuser}/#{repo_name}/" +
        'branches/ and rename the \'default\' branch to ' +
        "'#{upstream_branch}'. It will then give you some commands to " +
        'run to update this clone.',
      )
    end
  end
end
