import re
import string
from typing import Union, List

def normalize_answer(s):
    def remove_articles(text):
        return re.sub(r"\b(a|an|the)\b", " ", text)

    def white_space_fix(text):
        return " ".join(text.split())

    def remove_punc(text):
        exclude = set(string.punctuation)
        return "".join(ch for ch in text if ch not in exclude)

    def lower(text):
        return text.lower()

    return white_space_fix(remove_articles(remove_punc(lower(s))))

def get_em_score(prediction: Union[str, List[str]], ground_truths: Union[str, List[str], List[dict]], return_hit_count=False):
    if isinstance(prediction, str):
        prediction = [prediction]
    if isinstance(ground_truths, str):
        ground_truths = [(ground_truths, 0)]
    elif isinstance(ground_truths, list):
        if isinstance(ground_truths[0], str):
            ground_truths = [(gt, i) for i, gt in enumerate(ground_truths)]
        elif isinstance(ground_truths[0], dict):
            flat_ground_truths = list()
            for i, gt in enumerate(ground_truths):
                flat_ground_truths.append((gt['answer'], i))
                flat_ground_truths.extend([(alias, i) for alias in gt['aliases']])
            ground_truths = flat_ground_truths
        else:
            raise ValueError("unrecognized ground truth type")
    
    correct_count = 0
    prediction_set = set(prediction)
    hit_gt_idx = set()
    for pred in prediction_set:
        normalized_prediction = normalize_answer(pred)
        for ground_truth, gt_idx in ground_truths:
            normalized_ground_truth = normalize_answer(ground_truth)
            if normalized_ground_truth and normalized_prediction == normalized_ground_truth:
                correct_count += 1
                hit_gt_idx.add(gt_idx)
                break
    if return_hit_count:
        return correct_count, len(hit_gt_idx)
    else:
        return correct_count
