#!/usr/bin/python3
"""
Compile and run the primes.mixal sample program using mixvm and mixguile.
"""

import os
import subprocess
import sys
import tempfile


MIXASM = os.environ.get("TEST_MIXASM_PROG", "mixasm")
MIXVM = os.environ.get("TEST_MIXVM_PROG", "mixvm")
MIXGUILE = os.environ.get("TEST_MIXGUILE_PROG", "mixguile")

SRCDIR = os.environ.get("TEST_SRCDIR", ".")
SRCFILE = f"{SRCDIR}/samples/primes.mixal"

ENC = "us-ascii"


def test_primes() -> None:
    """ Primes sample program test: compile, run, check. """
    print("")
    if not os.path.isfile(SRCFILE):
        sys.exit(f'Not a file: "{SRCFILE}"; set TEST_SRCDIR?')

    with tempfile.TemporaryDirectory() as tmpdir:
        print(f"Using temporary directory {tmpdir}")

        os.mkdir(f"{tmpdir}/home")
        mix_env = dict(os.environ)
        mix_env.update({"HOME": f"{tmpdir}/home"})

        def examine_output(fname: str) -> None:
            """ Examine the primes output file. """
            print(f"Examining {fname}")
            with open(fname, mode="r", encoding=ENC) as printer_file:
                line = printer_file.readline()
                assert line.rstrip() == "FIRST FIVE HUNDRED PRIMES"

                found = {
                    "0002": False,
                    "0004": False,
                    "0239": False,
                    "0048": False,
                }
                print(f'Looking for {" ".join(sorted(found.keys()))}')
                for line in printer_file.readlines():
                    words = set(line.split())
                    for num in found:
                        if num in words:
                            assert not found[num]
                            found[num] = True

                print(f"Result: {found}")
                assert found == {
                    "0002": True,
                    "0004": False,
                    "0239": True,
                    "0048": False,
                }

        def run_program(program: str, subdir: str, commands: str) -> None:
            """ Create a subdir and input and output files, run a program. """
            program_dir = f"{tmpdir}/{subdir}"
            os.mkdir(program_dir)
            infname = f"{program_dir}/in.txt"
            with open(infname, mode="w+", encoding=ENC) as infile:
                print(commands, file=infile)
                infile.flush()
                infile.seek(0)
                print(f"Created {infname}")
                subprocess.check_call(["cat", "--", infname])

                outfname = f"{program_dir}/out.txt"
                with open(outfname, mode="w", encoding=ENC) as outfile:
                    print(f"Invoking {program} in {infname} out {outfname}")
                    subprocess.check_call(
                        [program],
                        shell=False,
                        env=mix_env,
                        stdin=infile,
                        stdout=outfile,
                    )
                print(f"Got {program} output:")
                subprocess.check_call(["cat", "--", outfname])

            assert sorted(os.listdir(f"{program_dir}")) == [
                "in.txt",
                "out.txt",
                "printer.dev",
            ]
            assert os.path.isfile(f"{program_dir}/printer.dev")
            examine_output(f"{program_dir}/printer.dev")

        program_base = f"{tmpdir}/primes"
        program_full = f"{program_base}.mix"
        print(f"Running {MIXASM} on {SRCFILE} to create {program_full}")
        subprocess.check_call([MIXASM, "-o", program_base, "--", SRCFILE])
        print(f"Checking for {program_full}")
        assert sorted(os.listdir(tmpdir)) == ["home", "primes.mix"]
        assert os.path.isfile(program_full)

        run_program(
            MIXVM,
            "mixvm",
            f"""load {program_base}
sddir {tmpdir}/mixvm
run""",
        )

        assert sorted(os.listdir(tmpdir)) == ["home", "mixvm", "primes.mix"]

        run_program(
            MIXGUILE,
            "mixguile",
            f"""(mix-load "{program_base}")
(mix-sddir "{tmpdir}/mixguile")
(mix-run)""",
        )

        assert sorted(os.listdir(tmpdir)) == [
            "home",
            "mixguile",
            "mixvm",
            "primes.mix",
        ]
