#!/usr/bin/env python3
"""Dieselben TBL-Bytes auf jedem Releaseziel: Linken und echte Standalone-Ausführung."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import platform
import shutil
import subprocess
import tempfile

DIGEST = '5d25c2f8c95ae535e55a6c84c1ddd0d964358863f4f3c780c50ac4a2eb3594df'
TARGETS = {
    ('Windows', 'AMD64'): 'x86_64-pc-windows-msvc',
    ('Darwin', 'arm64'): 'aarch64-apple-darwin',
    ('Linux', 'x86_64'): 'x86_64-unknown-linux-gnu',
    ('Linux', 'aarch64'): 'aarch64-unknown-linux-gnu',
}
SOURCE = '''COMMON SHARED shared&
OPEN "round.txt" FOR APPEND AS #1
old&=LOF(1)
PRINT #1, "x"
CLOSE #1
DIM a&(WIDTH)
DIM r AS Record
n&=3
CALL Work(a&(),r,n&)
PRINT a&(1);r.value;n&;shared&
PRINT r.text
IF old&=0 THEN RUN
END
'''
EXPECTED = b' 1 \n 7  3  9  1 \nTB  \n'  # RUN setzt auch den Textbildschirm zurück.


def run(args, cwd, env):
    result = subprocess.run([str(a) for a in args], cwd=cwd, env=env,
                            input=b'', capture_output=True, timeout=30)
    assert result.returncode == 0, (result.args, result.returncode, result.stdout, result.stderr)
    return result.stdout.replace(b'\r\n', b'\n')


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--bin-dir', type=Path, default=Path('target/release'))
    parser.add_argument('--library', type=Path, default=Path(__file__).resolve().parents[1] / 'libraries/portable.tbl')
    args = parser.parse_args()
    target = TARGETS.get((platform.system(), platform.machine()))
    assert target, f'Kein Releaseziel: {platform.system()} {platform.machine()}'
    digest = hashlib.sha256(args.library.read_bytes()).hexdigest()
    assert digest == DIGEST, f'Gemeinsames TBL-Artefakt verändert: {digest}'
    binaries = args.bin_dir.resolve()
    suffix = '.exe' if platform.system() == 'Windows' else ''
    compiler = binaries / ('tbc' + suffix)
    template_tool = binaries / ('tb-template' + suffix)
    env = dict(os.environ, PATH='')
    with tempfile.TemporaryDirectory(prefix='tb-library-') as work:
        root = Path(work)
        reference, clean = root / 'reference', root / 'clean'
        reference.mkdir()
        clean.mkdir()
        library = root / 'library.tbl'
        shutil.copyfile(args.library, library)
        template = root / ('runtime' + suffix)
        runtime = binaries / ('tbrt' + suffix)
        if not runtime.is_file():
            runtime = binaries / 'runtimes' / target / ('tbrt' + suffix)
        shutil.copy2(runtime, template)
        metadata = Path(str(runtime) + '.meta')
        if metadata.is_file():
            shutil.copyfile(metadata, Path(str(template) + '.meta'))
        else:
            run([template_tool, template, target], root, env)
        source = root / 'consumer.bas'
        source.write_text(SOURCE, encoding='utf-8')
        linked = root / 'consumer.tbc'
        run([compiler, 'link', source, library, '-o', linked], root, env)
        expected = run([compiler, 'run', linked], reference, env)
        assert expected == EXPECTED, expected
        executable = clean / ('consumer' + suffix)
        run([compiler, 'link', source, library, '--exe', '--target', target,
             '--template', template, '-o', executable], root, env)
        source.unlink()
        library.unlink()
        linked.unlink()
        template.unlink()
        Path(str(template) + '.meta').unlink()
        actual = run([executable], clean, env)
        assert actual == EXPECTED, actual
        assert (reference / 'round.txt').read_bytes() == (clean / 'round.txt').read_bytes()
        assert (clean / 'round.txt').read_text().splitlines() == ['x', 'x']
        assert sorted(p.name for p in clean.iterdir()) == ['consumer' + suffix, 'round.txt']
    print(json.dumps({'target': target, 'tbl_sha256': digest, 'native_execution': True,
                      'source_free': True, 'run_reset': True, 'output': actual.decode()}, ensure_ascii=False))


if __name__ == '__main__':
    main()
