import os
import json
from fuzzywuzzy import fuzz
import os
import json
import pandas as pd
def read_and_aggregate_results(base_path):
    all_results = []

    
    for subdir in os.listdir(base_path):
        subdir_path = os.path.join(base_path, subdir)
        if os.path.isdir(subdir_path):
            try:
                tokens, model = subdir.split('_', 1)
                tokens = int(tokens)
            except (ValueError, TypeError):
                tokens = -1
                model = subdir
            if tokens == -1:
                continue

            result = process_results(read_json_files(subdir_path))
            for model_name, metrics in result.items():
                metrics['Model'] = model_name
                metrics['Tokens'] = tokens

                for loc, values in metrics.items():
                    if loc not in ["Model", "Tokens"]:
                        values_flat = {
                            'Model': model_name,
                            'Tokens': tokens,
                            'Location': loc,
                            **values
                        }
                        all_results.append(values_flat)
           
            
    
    return all_results

    
    

    
    

    


def edit_similarity_score(pred, gt):
    pred = " ".join(pred) if isinstance(pred, list) else pred
    gt = " ".join(gt) if isinstance(gt, list) else gt
    es = fuzz.ratio(pred, gt)
    return es

def read_json_files(folder_path):
    json_files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith('.json')]
    data = []
    for file in json_files:
        idd = file.split('_')[0]
        with open(file, 'r') as f:
            json_data = json.load(f)
            json_data['file_name'] = os.path.basename(file)  
            data.append(json_data)
    return data

def get_field_value(item, field_name):
    if isinstance(item, dict):
        value = item.get(field_name, '')
        if isinstance(value, dict):
            value = next(iter(value.keys()), '')
        elif not isinstance(value, str):
            value = ''
        return value
    elif isinstance(item, str):
        return item
    else:
        return ''

def process_results(data):
    results = {}
    total_gt_combined = {"location_origin": [], "location_message": [], "location_ground": [], "location_ground_exp": []}
    total_pred_combined = {"location_origin": [], "location_message": [], "location_ground": [], "location_ground_exp": []}
    
    isNotLoads_total_scores = {"location_origin": [], "location_message": [], "location_ground": [], "location_ground_exp": []}

    for item in data:
        model_name = item['Results']['model']
        file_name = item['file_name']
        case_id = file_name.split('_')[0]  
        
        if model_name not in results:
            results[model_name] = {
                "location_origin": {"isLoads": 0, "isNotLoads": 0, "isNotLoads-ES": 0, "Loads": 0},
                "location_message": {"isLoads": 0, "isNotLoads": 0, "isNotLoads-ES": 0, "Loads": 0},
                "location_ground": {"isLoads": 0, "isNotLoads": 0, "isNotLoads-ES": 0, "Loads": 0},
                "location_ground_exp": {"isLoads": 0, "isNotLoads": 0, "isNotLoads-ES": 0, "Loads": 0}
            }
        
        for key in ['location_origin', 'location_message', 'location_ground', 'location_ground_exp']:
            pred_items = item['Results'][key]
            gt_items = item['Results']["location_ground_truth"]
            
            gt_combined_str = []
            pred_combined_str = []

            
            destination = 'content_change'
            
            for gt_item in gt_items:
                if not isinstance(gt_item.get(destination, {}), dict):  
                    continue
                filename = get_field_value(gt_item, 'file')
                
                for line_num in gt_item.get(destination, {}):
                    combined_string = "^".join([case_id, filename,  line_num])
                    gt_combined_str.append(combined_string)
            
            for pred_item in pred_items:
                
                if isinstance(pred_item, dict) and "location" in pred_item:
                    location_lines = pred_item['location']
                    
                else:
                    filename = get_field_value(pred_item, 'file')
                    
                    if isinstance(pred_item, dict) and pred_item.get(destination) is None:
                        combined_string = "^".join([case_id, filename,  ""])
                        pred_combined_str.append(combined_string)
                    elif isinstance(pred_item, dict):
                        for line_num in pred_item.get(destination, {}):
                            combined_string = "^".join([case_id, filename, line_num])
                            pred_combined_str.append(combined_string)

            total_gt_combined[key].extend(gt_combined_str)
            total_pred_combined[key].extend(pred_combined_str)
            
            if len(pred_items) == 1 and isinstance(pred_items, list) and isinstance(pred_items[0], dict) and "location" in pred_items[0]:
                location_text = pred_items[0]['location']
                for gt_item in gt_items:
                    content_all_text = ""
                    if isinstance(gt_item.get('content_all', {}), dict):
                        
                        
                        es = edit_similarity_score(location_text, json.dumps(gt_item, ensure_ascii=False))
                        isNotLoads_total_scores[key].append(es)
                results[model_name][key]['isNotLoads'] += 1
            else:
                results[model_name][key]['isLoads'] += 1

    
    for model in results:
        for key in ['location_origin', 'location_message', 'location_ground', 'location_ground_exp']:
            gt_list = total_gt_combined[key]
            pred_list = total_pred_combined[key]
            
            intersection = [item for item in gt_list if item in pred_list]
            
            if results[model][key]['isLoads'] > 0:
                precision = len(intersection) / len(pred_list) * 100 if pred_list else 0
                recall = len(intersection) / len(gt_list) * 100 if gt_list else 0
                micro_f1 = (2 * precision * recall / (precision + recall)) if (precision + recall) else 0
                
                results[model][key]['micro_f1'] = micro_f1
                results[model][key]['pre'] = precision
                results[model][key]['recall'] = recall
            
            if isNotLoads_total_scores[key]:
                results[model][key]['isNotLoads-ES'] = sum(isNotLoads_total_scores[key]) / len(isNotLoads_total_scores[key])
            results[model][key]['Loads'] = results[model][key]['isLoads'] / (results[model][key]['isLoads'] + results[model][key]['isNotLoads']) * 100
            results[model][key]['Sum'] = results[model][key]['isNotLoads'] + results[model][key]['isLoads']
    
    return results

def main():
    base_path = 'test_result_new'  
    

    results_loc = read_and_aggregate_results(base_path)

    
    results_df = pd.DataFrame(results_loc)

    
    results_df.to_csv('average_loc_results_by_model_and_token.csv', index=False)
    
    print("Average values calculated and saved to 'average_loc_results_by_model_and_token.csv'")

if __name__ == "__main__":
    main()

