#!/usr/bin/env vpython3
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Upload comments to gerrit.

mph = "make Peter happy".
Previously called mch ("make Casey happy").
"""

import os
import optparse
import re
import shutil
import sys


def _ensure_depot_tools():
  try:
    import gerrit_util
    import git_cl

    return
  except ImportError:
    pass

  script_dir = os.path.dirname(os.path.abspath(__file__))
  src_dir = os.path.abspath(os.path.join(script_dir, '..', '..', '..'))
  depot_tools_src = os.path.join(src_dir, 'third_party', 'depot_tools')
  if os.path.isdir(depot_tools_src) and depot_tools_src not in sys.path:
    sys.path.insert(0, depot_tools_src)

  gclient_bin = shutil.which('gclient')
  if gclient_bin:
    depot_tools_path = os.path.dirname(os.path.abspath(gclient_bin))
    if os.path.isdir(depot_tools_path) and depot_tools_path not in sys.path:
      sys.path.insert(0, depot_tools_path)


_ensure_depot_tools()

import codereview_parser

try:
  import gerrit_util
  import git_cl
except:
  print(
    'depot_tools not found; try appending the module path to your'
    + ' python path'
  )
  sys.exit(1)


def DieWithError(message):
  print(message, file=sys.stderr)
  sys.exit(1)


# These are additions to gerrit_util.py from depot_tools not yet ready to send
# out for review.
def CreateDraft(host, change, revision, path, line, msg=''):
  """Create a draft  gerrit comment."""
  path = 'changes/%s/revisions/%s/drafts' % (change, revision)
  body = {'path': path, 'line': line, 'message': msg, 'unresolved': True}
  conn = gerrit_util.CreateHttpConn(host, path, reqtype='PUT', body=body)
  return gerrit_util.ReadHttpJsonResponse(conn)


def SetReview(host, change, revision, msg, lgtm, comments):
  """Sets a review  in gerrit."""
  path = 'changes/%s/revisions/%s/review' % (change, revision)
  body = {'message': msg, 'comments': comments}
  if lgtm:
    body['labels'] = {'code-review': 1}

  conn = gerrit_util.CreateHttpConn(host, path, reqtype='POST', body=body)
  return gerrit_util.ReadHttpJsonResponse(conn)


class GerritParser(codereview_parser.Parser):
  def __init__(self, file):
    codereview_parser.Parser.__init__(self, file)
    self._HOST = 'chromium-review.googlesource.com'
    self._issue_number = 0
    self._patchset = 0
    self._change_id = ''
    self._revision_id = ""
    self._overall_comment = ''
    self._comments = {}

  def OnError(self, msg):
    DieWithError(msg)

  def OnPreambleLine(self, line):
    matcher = re.match('Issue: (\d+), patchset: (\d+)', line)
    if matcher:
      self._issue_number = int(matcher.groups()[0])
      self._patchset = int(matcher.groups()[1])
      self._change_id = gerrit_util.GetChange(self._HOST, self._issue_number)[
        'change_id'
      ]
      self._revision_id = gerrit_util.GetChangeCurrentRevision(
        self._HOST, self._change_id
      )[0]['current_revision']

  def OnFinishPreamble(self):
    pass

  def OnOverallComment(self, comment):
    self._overall_comment = comment

  def OnFileComment(self, path, line, text, comment):
    if not path in self._comments:
      self._comments[path] = []

    self._comments[path].append(
      {'message': comment, 'line': line, 'unresolved': True}
    )

  def OnParseFinished(self):
    is_lg = re.match(".*lgtm.*", self._overall_comment, re.IGNORECASE)
    SetReview(
      self._HOST,
      self._change_id,
      self._revision_id,
      self._overall_comment,
      is_lg,
      self._comments,
    )
    print('Done')

  def Parse(self):
    codereview_parser.Parser.Parse(self)
    self.OnParseFinished()

  def add_comment(self, issue, message, add_as_reviewer=False):
    max_message = 10000
    tail = '...\n(message too large)'
    if len(message) > max_message:
      message = message[: max_message - len(tail)] + tail

    issue_props = self._rd.get_issue_properties(self._issue_number, None)
    reviewers = ','.join(issue_props['reviewers'])
    cc = ','.join(issue_props['cc'])
    self._rd.post(
      '/%d/publish' % issue,
      [
        ('xsrf_token', self._rd.xsrf_token()),
        ('message', message),
        ('message_only', 'False'),
        ('add_as_reviewer', str(bool(add_as_reviewer))),
        ('reviewers', reviewers),
        ('cc', cc),
        ('send_mail', 'True'),
        ('no_redirect', 'True'),
      ],
    )


def ProcessFile(file):
  parser = GerritParser(file)
  parser.Parse()


def main(argv):
  parser = optparse.OptionParser()
  parser.add_option('-f', '--file')
  options, args = parser.parse_args(argv)
  file_name = options.file
  if file_name is None:
    if len(argv) != 1:
      parser.print_help()
      DieWithError('Review file not specified')
    file_name = argv[0]
  with open(file_name) as file:
    ProcessFile(file)


if __name__ == '__main__':
  main(sys.argv[1:])
