import json
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

from matplotlib.dates import MONTHLY, WEEKLY, DateFormatter, rrulewrapper, RRuleLocator
from pandas.plotting import register_matplotlib_converters
import re
from mongoengine import connect, DoesNotExist
from pycoshark.mongomodels import Commit, FileAction, File, Project, VCSSystem, Hunk, Issue, IssueSystem, Refactoring
from pycoshark.utils import create_mongodb_uri_string, java_filename_filter
from bson import json_util
from scipy import stats
from scipy import optimize
from autorank._util import _confidence_interval
from itertools import chain


with open('labels.json', 'r') as file:
    completed = json_util.loads(file.read())

confidence_level = 1-(0.05/45)

for result in completed:
    labels = result['lines_manual']
    first_labels = next(iter(labels.values()))
    lines = []
    for cur_lines in first_labels.values():
        lines.extend(cur_lines)
    
    label_dict = {}
    label_dict_consensus = {}
    for line in lines:
        label_dict[line] = {'bugfix':0, 'whitespace':0, 'documentation':0, 'refactoring':0, 'test':0, 'unrelated':0}
    for user, user_labels in labels.items():
        for label_type, label_lines in user_labels.items():
            if label_type=='bug':
                label_type='bugfix'
                print(result)
            for label_line in label_lines:
                label_dict[label_line][label_type] += 1
    for line, line_labels in label_dict.items():
        has_consensus = False
        for label_type, count in line_labels.items():
            if count>=3:
                # we need this part due to our training issues
                if has_consensus:
                    if count>consensus_count:
                        consensus_count = count
                        label_dict_consensus[line] = label_type                        
                label_dict_consensus[line] = label_type
                has_consensus = True
                consensus_count = count
        if not has_consensus:
            is_java_file = java_filename_filter(result['file'], production_only=False)
            is_prod_file = java_filename_filter(result['file'], production_only=True)
            is_test_file = is_java_file and not is_prod_file
            if is_test_file and line_labels['test']+line_labels['whitespace']+line_labels['documentation']>=4:
                label_dict_consensus[line] = 'test_doc_whitespace'
            elif line_labels['bugfix']==0:
                label_dict_consensus[line] = 'no_bugfix'
            else:
                label_dict_consensus[line] = 'None'
    result['label_dict'] = label_dict
    result['label_dict_consensus'] = label_dict_consensus
    label_dict_by_type = {}
    for line, label in label_dict_consensus.items():
        if label not in label_dict_by_type:
            label_dict_by_type[label] = []
        label_dict_by_type[label].append(line)
    result['label_dict_by_type'] = label_dict_by_type

commit_ratios_all = {}
commit_ratios_java = {}
commit_ratios_prod = {}
for result in completed:
    if result['revision_hash'] not in commit_ratios_all:
        commit_ratios_all[result['revision_hash']] = {}
        #commit_ratios_java[result['revision_hash']] = {}
        #commit_ratios_prod[result['revision_hash']] = {}
    for label, lines in result['label_dict_by_type'].items():
        if label not in commit_ratios_all[result['revision_hash']]:
            commit_ratios_all[result['revision_hash']][label] = 0
        commit_ratios_all[result['revision_hash']][label] += len(lines)
        if java_filename_filter(result['file'], production_only=False):
            if result['revision_hash'] not in commit_ratios_java:
                commit_ratios_java[result['revision_hash']] = {}
            if label not in commit_ratios_java[result['revision_hash']]:
                commit_ratios_java[result['revision_hash']][label] = 0
            commit_ratios_java[result['revision_hash']][label] += len(lines)
        if java_filename_filter(result['file'], production_only=True):
            if result['revision_hash'] not in commit_ratios_prod:
                commit_ratios_prod[result['revision_hash']] = {}
            if label not in commit_ratios_prod[result['revision_hash']]:
                commit_ratios_prod[result['revision_hash']][label] = 0
            commit_ratios_prod[result['revision_hash']][label] += len(lines)

        
commit_ratios_all_df = pd.DataFrame(commit_ratios_all).fillna(0).transpose()
commit_ratios_all_df = commit_ratios_all_df.div(commit_ratios_all_df.sum(axis=1), axis=0)

commit_ratios_java_df = pd.DataFrame(commit_ratios_java).fillna(0).transpose()
commit_ratios_java_df = commit_ratios_java_df.div(commit_ratios_java_df.sum(axis=1), axis=0).fillna(0)

commit_ratios_prod_df = pd.DataFrame(commit_ratios_prod).fillna(0).transpose()
commit_ratios_prod_df = commit_ratios_prod_df.div(commit_ratios_prod_df.sum(axis=1), axis=0).fillna(0)
commit_ratios_prod_df['total_lines'] = pd.DataFrame(commit_ratios_prod).fillna(0).transpose().sum(axis=1)



for column in commit_ratios_all_df.columns:
    if column not in commit_ratios_java_df.columns:
        commit_ratios_java_df[column] = 0.0
    if column not in commit_ratios_prod_df.columns:
        commit_ratios_prod_df[column] = 0.0

# create stats table
col_order = ['bugfix', 'test', 'documentation', 'refactoring', 'unrelated', 'whitespace', 'test_doc_whitespace', 'no_bugfix', 'None']
box_labels = ['Bugfix', 'Test', 'Documentation', 'Refactoring', 'Unrelated Improvement', 'Whitespace', 'Test/Doc/Whitespace', 'No Bugfix', 'No Consensus']

for col, label in zip(col_order, box_labels):
    lower_all, upper_all = _confidence_interval(commit_ratios_all_df[col], 1-confidence_level, is_normal=False)
    lower_prod, upper_prod = _confidence_interval(commit_ratios_prod_df[col], 1-confidence_level, is_normal=False)
    gt_zero = sum(commit_ratios_prod_df[col]>0)/len(commit_ratios_prod_df)
    print("%22s , %3d , %3d , [%3d, %3d] , %3d , %3d , [%3d, %3d] , %3d" % 
          (label,
           100*commit_ratios_all_df[col].median(),
           100*stats.median_abs_deviation(commit_ratios_all_df[col], scale=1/1.4826),
           100*lower_all, 100*upper_all,
           100*commit_ratios_prod_df[col].median(),
           100*stats.median_abs_deviation(commit_ratios_prod_df[col], scale=1/1.4826),
           100*lower_prod, 100*upper_prod,
           100*gt_zero))
    
