#!/usr/bin/env python3

# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# Use this script to update
# https://wiki.documentfoundation.org/MissingUnitTests

import os
import datetime
import subprocess
import sys
import re
import json
import requests

def splitList(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

def whiteboardNotes(whiteboard):
    if not whiteboard:
        return ''
    if ' ' in whiteboard:
        whiteboardList = reversed(whiteboard.split(' '))
        for w in whiteboardList:
            if w.startswith("unitTestNotes"):
                return w.split(':')[1]
    elif whiteboard.startswith("unitTestNotes"):
        return whiteboard.split(':')[1]

    return ''

def main(ignoredBugs):
    results = {
        'export': {
            'docx': {},
            'doc': {},
            'pptx': {},
            'xlsx': {},
            'xhtml': {},
            'html': {},
        },
        'writer': {
            'undo': {},
            'autoformat': {},
            'autocorrect': {},
            'others': {},
        },
        'calc': {
            'import': {},
            'format': {},
            'others': {},
        },
        'impress': {
            'drawingml': {},
            'slidesorter': {},
            'others': {},
        },

    }
    hasTestSet = set()

    repoPath = os.path.dirname(os.path.abspath(__file__)) + '/..'
    branch = subprocess.check_output(
            ['git', '-C', repoPath, 'rev-parse', '--abbrev-ref', 'HEAD'],
            stderr=subprocess.DEVNULL)
    last_hash = subprocess.check_output(
            ['git', '-C', repoPath, 'rev-parse', 'HEAD'],
            stderr=subprocess.DEVNULL)
    output = subprocess.check_output(
            ['git', '-C', repoPath, 'log', '--since="2012-01-01', '--name-only' ,'--pretty=format:"%s%n%ad"', '--date=format:"%Y/%m/%d"'],
            stderr=subprocess.DEVNULL)
    commits = output.decode('utf-8', 'ignore').split('\n\n')

    for commit in reversed(commits):

        commitInfo = commit.split('\n')

        summary = commitInfo[0].strip('"').lower()

        # Check for bugIds in the summary. Ignore those with a '-' after the digits.
        # Those are used for file names ( e.g. tdf129410-1.ods )
        bugIds = re.findall("\\b(?:bug|fdo|tdf|lo)[#:]?(\\d+)(?!-)\\b", summary)
        if bugIds is None or len(bugIds) == 0:
            continue

        for bugId in bugIds:

            isIgnored = False
            for i in ignoredBugs:
                if i in summary:
                    isIgnored = True
            if isIgnored:
                continue

            if bugId in hasTestSet:
                continue

            date = commitInfo[1].strip('"')
            infoList = [date, summary]

            changedFiles = "".join(commitInfo[2:])
            if 'qa' in changedFiles:
                hasTestSet.add(bugId)
                continue

            elif 'sw/source/filter/ww8/docx' in changedFiles or \
                    'writerfilter/source/dmapper' in changedFiles or \
                    'starmath/source/ooxmlimport' in changedFiles:
                results['export']['docx'][bugId] = infoList

            elif 'sw/source/filter/ww8/ww8' in changedFiles:
                results['export']['doc'][bugId] = infoList

            elif 'sc/source/filter/excel/xe' in changedFiles:
                results['export']['xlsx'][bugId] = infoList

            elif 'oox/source/export/' in changedFiles:
                results['export']['pptx'][bugId] = infoList

            elif 'filter/source/xslt/odf2xhtml/export' in changedFiles:
                results['export']['xhtml'][bugId] = infoList

            elif 'sw/source/filter/html/' in changedFiles:
                results['export']['html'][bugId] = infoList

            elif 'sw/source/core/undo/' in changedFiles:
                results['writer']['undo'][bugId] = infoList

            elif 'sw/source/core/edit/autofmt' in changedFiles:
                results['writer']['autoformat'][bugId] = infoList

            elif 'sw/source/core/edit/acorrect' in changedFiles:
                results['writer']['autocorrect'][bugId] = infoList

            elif 'drawingml' in changedFiles:
                results['impress']['drawingml'][bugId] = infoList

            elif 'sd/source/ui/slidesorter/' in changedFiles:
                results['impress']['slidesorter'][bugId] = infoList

            elif 'sc/source/core/tool/interpr' in changedFiles:
                results['calc']['import'][bugId] = infoList

            elif 'svl/source/numbers/' in changedFiles:
                results['calc']['format'][bugId] = infoList

            # Keep the following if statements at the end

            elif 'sc/source/core/' in changedFiles:
                results['calc']['others'][bugId] = infoList

            elif 'sw/source/core/' in changedFiles:
                results['writer']['others'][bugId] = infoList

            elif 'sd/source/core/' in changedFiles:
                results['impress']['others'][bugId] = infoList

    listOfBugIdsWithoutTest = []
    for k,v in results.items():
        for k1, v1 in v.items():
            for bugId, info in v1.items():
                if bugId not in hasTestSet:
                    listOfBugIdsWithoutTest.append(bugId)


    bugzillaJson = []
    resultList = []
    fixList = []
    #Split the list into different chunks for the requests, otherwise it fails
    for chunk in splitList(listOfBugIdsWithoutTest, 50):
        urlGet = 'https://bugs.documentfoundation.org/rest/bug?id=' + ','.join(chunk)
        rGet = requests.get(urlGet)
        rawData = json.loads(rGet.text)
        rGet.close()
        bugzillaJson.extend(rawData['bugs'])

    for k,v in results.items():
        for k1, v1 in v.items():
            for bugId, info in v1.items():

                resolution = ''
                keywords = []
                priority = ''
                notes = ''
                for bug in bugzillaJson:
                    if str(bug['id']) == str(bugId):
                        resolution = bug['resolution']
                        keywords = bug['keywords']
                        priority = bug['priority']
                        notes = whiteboardNotes(bug['whiteboard'])
                        break

                # Only care about FIXED bugs
                # Ignore performance bugs and accessibility bugs
                if resolution and resolution == 'FIXED' and 'perf' not in keywords \
                        and 'accessibility' not in keywords:
                    fixList.append({
                        "id": bugId,
                        "date": info[0],
                        "priority": priority.upper(),
                        "summary": info[1],
                        "maintopic":k,
                        "subtopic":k1,
                        "notes": notes
                    })

    resultList.append([{
        "Generator": os.path.basename(sys.argv[0]),
        "Date": str(datetime.datetime.now()),
        "Commits": str(len(commits)),
        "Branch": branch.decode().strip(),
        "Hash": str(last_hash.decode().strip()),
    }])
    resultList.append(fixList)
    print(json.dumps(resultList))

def usage():
    message = """usage: {program} [bugs to ignore (each one is one argument)]

Sample: {program} 10000 10001 10002"""
    print(message.format(program = os.path.basename(sys.argv[0])))

if __name__ == '__main__':

    args = set()
    if len(sys.argv) > 1:
        arg1 = sys.argv[1]
        if arg1 == '-h' or arg1 == "--help":
            usage()
            sys.exit(1)
        for i in sys.argv:
            if i.isdigit():
                args.add(i)

    main(sorted(args))