import collections


def wer_details_by_speaker(details_by_utterance, utt2spk):
    """Compute word error rate and another salient info grouping by speakers.

    Arguments
    ---------
    details_by_utterance : list
        See the output of wer_details_by_utterance
    utt2spk : dict
        Map from utterance id to speaker id


    Returns
    -------
    dict
        Maps speaker id to a dictionary of the statistics, with keys:

        * "speaker": Speaker id,
        * "num_edits": (int) Number of edits in total by this speaker.
        * "insertions": (int) Number insertions by this speaker.
        * "dels": (int) Number of deletions by this speaker.
        * "subs": (int) Number of substitutions by this speaker.
        * "num_scored_tokens": (int) Number of scored reference
          tokens by this speaker (a missing hypothesis might still
          have been scored with 'all' scoring mode).
        * "num_scored_sents": (int) number of scored utterances
          by this speaker.
        * "num_erraneous_sents": (int) number of utterance with at least
          one error, by this speaker.
        * "num_absent_sents": (int) number of utterances for which no
          hypotheses was found, by this speaker.
        * "num_ref_sents": (int) number of utterances by this speaker
          in total.
    """
    # Build the speakerwise details:
    details_by_speaker = {}
    for dets in details_by_utterance:
        speaker = utt2spk[dets["key"]]
        spk_dets = details_by_speaker.setdefault(
            speaker,
            collections.Counter(
                {
                    "speaker": speaker,
                    "insertions": 0,
                    "dels": 0,
                    "subs": 0,
                    "num_scored_tokens": 0,
                    "num_scored_sents": 0,
                    "num_edits": 0,
                    "num_erraneous_sents": 0,
                    "num_absent_sents": 0,
                    "num_ref_sents": 0,
                }
            ),
        )
        utt_stats = collections.Counter()
        if dets["hyp_absent"]:
            utt_stats.update({"num_absent_sents": 1})
        if dets["scored"]:
            utt_stats.update(
                {
                    "num_scored_sents": 1,
                    "num_scored_tokens": dets["num_ref_tokens"],
                    "insertions": dets["insertions"],
                    "dels": dets["deletions"],
                    "subs": dets["substitutions"],
                    "num_edits": dets["num_edits"],
                }
            )
            if dets["num_edits"] > 0:
                utt_stats.update({"num_erraneous_sents": 1})
        spk_dets.update(utt_stats)
    # We will in the end return a list of normal dicts
    # We want the output to be sortable
    details_by_speaker_dicts = []
    # Now compute speakerwise summary details
    for speaker, spk_dets in details_by_speaker.items():
        spk_dets["speaker"] = speaker
        if spk_dets["num_scored_sents"] > 0:
            spk_dets["WER"] = (
                100.0 * spk_dets["num_edits"] / spk_dets["num_scored_tokens"]
            )
            spk_dets["SER"] = (
                100.0
                * spk_dets["num_erraneous_sents"]
                / spk_dets["num_scored_sents"]
            )
        else:
            spk_dets["WER"] = None
            spk_dets["SER"] = None
        details_by_speaker_dicts.append(spk_dets)
    return details_by_speaker_dicts