import argparse
from pathlib import Path
import re
from time import perf_counter
import unicodedata

from faster_whisper import WhisperModel
from transcribe_notes import transcribe


def words(text):
    return re.findall(r"[^\W_]+", unicodedata.normalize("NFC", text).casefold())


def edit_distance(expected, observed):
    previous = list(range(len(observed) + 1))
    for row, target in enumerate(expected, start=1):
        current = [row]
        for column, guess in enumerate(observed, start=1):
            current.append(min(
                previous[column] + 1,
                current[column - 1] + 1,
                previous[column - 1] + (target != guess),
            ))
        previous = current
    return previous[-1]


def evaluate(audio, model_name, language, reference, facts):
    model = WhisperModel(model_name, device="cpu", compute_type="int8", local_files_only=True)
    started = perf_counter()
    lines, detected = transcribe(model, audio, language, vad_filter=True)
    elapsed = perf_counter() - started
    text = " ".join(line for _, line in lines)
    observed = words(text)
    edits = edit_distance(reference, observed)
    normalized = " " + " ".join(observed) + " "
    matches = [label for label, tokens in facts if " " + " ".join(tokens) + " " in normalized]
    print(f"Model: {model_name} | language used: {detected} | transcribe: {elapsed:.2f}s")
    print(f"Transcript: {text or '(no speech)'}")
    print(f"Word error rate: {edits}/{len(reference)} = {edits / len(reference):.1%}")
    if facts:
        print("Key phrase:", " / ".join(matches) if matches else "missing")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Check a local transcript against reference words.")
    parser.add_argument("audio", type=Path)
    parser.add_argument("--reference", required=True)
    parser.add_argument("--model", choices=("tiny.en", "tiny"), default="tiny")
    parser.add_argument("--language", choices=("en", "es", "auto"), default="auto")
    parser.add_argument("--fact", action="append", default=[], help="Repeat for alternate spellings of one fact")
    args = parser.parse_args()
    reference = words(args.reference)
    facts = [(label, words(label)) for label in args.fact]
    if not args.audio.is_file() or not reference or any(not tokens for _, tokens in facts):
        parser.error("Supply a recording, a nonempty reference, and any key phrases.")
    if args.model == "tiny.en" and args.language == "es":
        parser.error("Use the multilingual tiny model for Spanish.")
    language = None if args.language == "auto" else args.language
    try:
        evaluate(args.audio, args.model, language, reference, facts)
    except (OSError, RuntimeError, ValueError) as error:
        raise SystemExit(str(error)) from None
