# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from common.findit_http_client import FinditHttpClient
from gae_libs import token
from gae_libs.gitiles.cached_gitiles_repository import CachedGitilesRepository
from gae_libs.handlers.base_handler import BaseHandler
from gae_libs.handlers.base_handler import Permission
from model.wf_analysis import WfAnalysis
from waterfall import buildbot
from waterfall import build_util


def _GetFirstFailedBuild(master_name, builder_name, build_number):
  """Checks failed_steps for current_build and finds the first failed build."""
  analysis = WfAnalysis.Get(master_name, builder_name, build_number)
  if not analysis or not analysis.result['failures']:
    return None, None

  start_build_number = build_number
  failed_steps = []
  for failure in analysis.result['failures']:
    failed_steps.append(failure['step_name'])
    if failure['last_pass'] and failure['last_pass'] + 1 < start_build_number:
      start_build_number = failure['last_pass'] + 1
      continue
    if failure['first_failure'] < start_build_number:
      start_build_number = failure['first_failure']

  return start_build_number, failed_steps


def _AllFailedStepsPassed(passed_steps, current_failed_steps):
  for current_failed_step in current_failed_steps:
    if current_failed_step not in passed_steps:
      return False
  return True


def GetPossibleRevertInfoFromRevision(revision):
  """Parse message to get information of reverting and reverted cls."""
  git_repo = CachedGitilesRepository(
      FinditHttpClient(), 'https://chromium.googlesource.com/chromium/src.git')
  change_log = git_repo.GetChangeLog(revision)
  if not change_log:  # pragma: no cover
    return {}

  reverted_revision = change_log.reverted_revision
  if not reverted_revision:
    return {}

  reverted_cl_change_log = git_repo.GetChangeLog(reverted_revision)

  data = {
      'action':
          'Reverted',
      'fixed_revision':
          reverted_revision,
      'fixed_cl_review_url': (reverted_cl_change_log.code_review_url
                              if reverted_cl_change_log else None),
      'fixed_cl_commit_position': (reverted_cl_change_log.commit_position
                                   if reverted_cl_change_log else None),
      'fixing_revision':
          revision,
      'fixing_cl_review_url':
          change_log.code_review_url,
      'fixing_cl_commit_position':
          change_log.commit_position
  }
  return data


def _CheckReverts(master_name, builder_name, current_build_number):
  """Checks each cl in current build to see if some of them are reverted.

  Returns:
      [
          {
              'action': 'Reverted',
              'fixed_cl_commit_position': '341992',
              'fixed_revision': 'c9cc182781484f9010f062859cda048afef',
              'fixed_cl_review_url': (
                 'https://codereview.chromium.org/1278653002'),
              'fixing_build_number': 0,
              'fixing_build_url': (
                  'https://luci-milo.appspot.com/buildbot/m/b/0')
              'fixing_revision': '208c65020aecfcf305d524058f7ca89363',
              'fixing_cl_commit_position': '342013',
              'fixing_cl_review_url': (
                 'https://codereview.chromium.org/1278653005'),
              'fixing_build_number': 2,
              'fixing_build_url': (
                  'https://luci-milo.appspot.com/buildbot/m/b/2')
          },
          ...
      ]
  """
  reverted_cls = []
  blamed_cls = {}
  steps_pass = False

  build_number, current_failed_steps = _GetFirstFailedBuild(
      master_name, builder_name, current_build_number)
  if not build_number:
    return []

  while not steps_pass:
    # Breaks the loop after the first green build
    # or all the current failed steps pass.
    build = build_util.DownloadBuildData(master_name, builder_name,
                                         build_number)
    if not build or not build.data:
      return []

    build_info = buildbot.ExtractBuildInfo(master_name, builder_name,
                                           build_number, build.data)
    if build_number <= current_build_number:
      # All the cls in builds prior to the current build(included)
      # should be checked for reverts.
      for blamed_revision in build_info.blame_list:
        blamed_cls[blamed_revision] = build_number
    if (build_info.result == 0 or
        _AllFailedStepsPassed(build_info.passed_steps, current_failed_steps)):
      steps_pass = True

    for cl_in_blame_list in build_info.blame_list:
      cls_info = GetPossibleRevertInfoFromRevision(cl_in_blame_list)
      if not cls_info:
        continue

      fixed_revision = cls_info['fixed_revision']
      if (fixed_revision in blamed_cls and
          build_number > blamed_cls[fixed_revision] and
          build_number > current_build_number):
        # If a CL and its reverting cl are in the same build,
        # it doesn't have any impact on the build failure.
        # And possible fix should take effect after the current build.
        cls_info['fixed_build_number'] = blamed_cls[fixed_revision]
        cls_info['fixed_build_url'] = (buildbot.CreateBuildUrl(
            master_name, builder_name, blamed_cls[fixed_revision]))
        cls_info['fixing_build_number'] = build_number
        cls_info['fixing_build_url'] = (buildbot.CreateBuildUrl(
            master_name, builder_name, build_number))
        reverted_cls.append(cls_info)
    build_number += 1

  reverted_cls.sort(key=lambda x: x['fixed_cl_commit_position'])
  return reverted_cls


class HelpTriage(BaseHandler):
  PERMISSION_LEVEL = Permission.ADMIN

  @token.VerifyXSRFToken()
  def HandlePost(self):
    """Returns information to help triage the analysis results.

    1. Checks if any CL in current build is reverted in later builds
    up until the first green build(included).
    2. TODO: Checks if any changed file in current build is changed again in
    later builds up until the first green build(included).
    """
    url = self.request.get('url').strip()
    build_keys = buildbot.ParseBuildUrl(url)

    if not build_keys:  # pragma: no cover
      return {'data': {}}

    data = _CheckReverts(*build_keys)

    return {'data': data}
