#!/usr/bin/env python3

import collections
import json
import subprocess
import sys

DEFAULT_REF = 'origin/master'

def get_diff_ranges(ref=DEFAULT_REF):
    '''Get chunks affected by a merge request

    Args:
        ref (str): a reference to diff the HEAD against (default: origin/master)

    Returns:
        dict: a dict with filenames in keys and list of `(start, end)` ranges in
            values (start is inclusive, end is not, wrt :py:func:`range`)
    '''
    files = collections.defaultdict(list)
    data = subprocess.check_output(['git', 'diff', '-U0', ref, 'HEAD']).decode()
    path = None

    for line in data.split('\n'):
        if line.startswith('+++ '):
            path = (None if line == '+++ /dev/null'
                else line.split('/', maxsplit=1)[-1])
            continue
        if line.startswith('@@ '):
            # @@ -8,0 +9 @@ [class name or previous line or whatever]
            if path is None: # /dev/null
                continue
            _, _, plus, *_ = line.split()
            start, length, *_ = *(int(i) for i in plus[1:].split(',')), 1
            if not length:
                # remove-only chunk
                continue
            files[path].append((start, start + length))

    return files

class Diff:
    '''A quick and dirty diff evaluator

    >>> diff = Diff()
    >>> (message['file'], message['line']) in diff
    True # or False

    The default diff is to the ``origin/master`` ref.
    '''
    # pylint: disable=too-few-public-methods

    def __init__(self, ref=DEFAULT_REF):
        self._files = get_diff_ranges(ref)

    def __contains__(self, pathline):
        path, line = pathline
        try:
            return any(start <= line < end for start, end in self._files[path])
        except KeyError:
            return False

def main():
    diff = Diff()
    with sys.stdin:
        pylint = json.load(sys.stdin)

    ret = 0
    for message in pylint:
        # shellcheck
        if 'path' not in message:
            message['path'] = message['file']
        if 'symbol' not in message:
            message['symbol'] = message['code']

        if (message['path'], message['line']) in diff:
            if not ret:
                print('MESSAGES AFFECTING THIS PR:')
            print('{path} +{line}:{column}: {symbol}: {message}'.format(
                **message))
            ret += 1

    return min(ret, 255)

if __name__ == '__main__':
    sys.exit(main())
