"""
Golden tests for the fpy compiler.

These tests compile simple fpy programs and compare the generated bytecode
against expected output stored in golden files.

Golden files are stored in test/fpy/golden/ with:
- <name>.fpy: The source file to compile
- <name>.fpybc: The expected bytecode output
"""

import pytest
from pathlib import Path

import fpy.error
from fpy.compiler import text_to_ast, ast_to_directives
from fpy.bytecode.assembler import directives_to_fpybc


GOLDEN_DIR = Path(__file__).parent / "golden"

# Path to the test dictionary
DEFAULT_DICTIONARY = str(
    Path(__file__).parent / "RefTopologyDictionary.json"
)


def compile_to_fpybc(source: str) -> str:
    """Compile fpy source code to fpybc bytecode text."""
    fpy.error.file_name = "<golden-test>"
    fpy.error.input_text = source
    fpy.error.input_lines = source.splitlines()
    
    body = text_to_ast(source)
    assert body is not None, "Parsing failed"
    
    directives = ast_to_directives(body, DEFAULT_DICTIONARY)
    assert not isinstance(directives, (fpy.error.CompileError, fpy.error.BackendError)), \
        f"Compilation failed: {directives}"
    
    return directives_to_fpybc(directives)


def get_golden_test_cases():
    """Find all golden test cases (pairs of .fpy and .fpybc files)."""
    if not GOLDEN_DIR.exists():
        return []
    
    test_cases = []
    for fpy_file in sorted(GOLDEN_DIR.glob("*.fpy")):
        fpybc_file = fpy_file.with_suffix(".fpybc")
        if fpybc_file.exists():
            test_cases.append(fpy_file.stem)
    return test_cases


@pytest.mark.parametrize("test_name", get_golden_test_cases())
def test_golden(test_name: str):
    """
    Golden test: compile the .fpy file and compare against the .fpybc file.
    """
    fpy_file = GOLDEN_DIR / f"{test_name}.fpy"
    fpybc_file = GOLDEN_DIR / f"{test_name}.fpybc"
    
    source = fpy_file.read_text()
    expected = fpybc_file.read_text()
    
    actual = compile_to_fpybc(source)
    
    assert actual == expected, (
        f"Golden test '{test_name}' failed.\n"
        f"Expected:\n{expected}\n"
        f"Actual:\n{actual}\n"
    )


def update_golden(test_name: str):
    """
    Utility to update a golden file. Run manually if needed.
    """
    fpy_file = GOLDEN_DIR / f"{test_name}.fpy"
    fpybc_file = GOLDEN_DIR / f"{test_name}.fpybc"
    
    source = fpy_file.read_text()
    actual = compile_to_fpybc(source)
    
    fpybc_file.write_text(actual)
    print(f"Updated {fpybc_file}")


def update_all_golden_seqs():
    """
    Utility to update all golden files. Run manually if needed.
    """
    for fpy_file in sorted(GOLDEN_DIR.glob("*.fpy")):
        test_name = fpy_file.stem
        update_golden(test_name)
