"""Explicit grader amendment wrapper; original experimental files stay frozen.

Exact modular inequality certificates precede the supplied grader. Unresolved
slow grades raise and stop the job; a timeout never supplies a reward bit.
"""
import argparse
import json
from pathlib import Path
import runpy
import signal
import sys
import time

from certified_integer_grade import unequal_certificate


class UnresolvedGrade(RuntimeError):
    pass


def guarded_grader(original, normalize, log_path, seconds=5):
    assert seconds > 0

    def log(record):
        with log_path.open('a') as f:
            f.write(json.dumps(record)+'\n')

    def grade(prediction, reference):
        certificate = unequal_certificate(normalize(prediction), normalize(reference))
        if certificate is not None:
            log(dict(status='certified_unequal', prediction=prediction, reference=reference,
                     certificate=certificate, time=time.time()))
            return False

        def expired(signum, frame):
            raise UnresolvedGrade('Supplied symbolic grading exceeded time budget; no grade emitted')

        old_handler = signal.getsignal(signal.SIGALRM)
        old_timer = signal.getitimer(signal.ITIMER_REAL)
        assert old_timer == (0.0, 0.0), 'Do not overwrite an active timer'
        signal.signal(signal.SIGALRM, expired)
        signal.setitimer(signal.ITIMER_REAL, seconds)
        started = time.perf_counter()
        try:
            return original(prediction, reference)
        except UnresolvedGrade:
            log(dict(status='unresolved_timeout', prediction=prediction, reference=reference,
                     seconds=time.perf_counter()-started, time=time.time()))
            raise
        finally:
            signal.setitimer(signal.ITIMER_REAL, 0)
            signal.signal(signal.SIGALRM, old_handler)
    return grade


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--certificate-log', type=Path, required=True)
    parser.add_argument('script', type=Path)
    parser.add_argument('arguments', nargs=argparse.REMAINDER)
    args = parser.parse_args()
    args.certificate_log.parent.mkdir(parents=True, exist_ok=True)
    import run_baseline as base
    from reasoning_from_scratch import ch03
    grade = guarded_grader(ch03.grade_answer, ch03.normalize_text, args.certificate_log)
    ch03.grade_answer = grade
    base.grade_answer = grade
    sys.argv = [str(args.script), *args.arguments]
    runpy.run_path(str(args.script), run_name='__main__')


if __name__ == '__main__':
    main()
