import pytest
import sys
import os


sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from vsc.compiler import compile_valuascript
from vsc.exceptions import ValuaScriptError


from tests.test_integration import find_engine_path, run_preview_integration

BASE_SCRIPT = "@iterations=1\n@output=result\n"


def test_udf_calling_builtin_with_multi_return():
    """
    BUG FIX TEST: Validates that a UDF can contain a multi-assignment
    statement that calls a built-in function returning a tuple.
    This directly tests the scenario that was causing the KeyError.
    """
    script = """
    @iterations=1
    @output=amortization_value

    func calculate_rd_amortization(current_rd: scalar, past_rd: vector, life: scalar) -> scalar {
        # This multi-assignment was the source of the bug
        let cap_asset, amortization = capitalize_expense(current_rd, past_rd, life)
        return amortization
    }

    let p_rd = [100, 110]
    let amortization_value = calculate_rd_amortization(130, p_rd, 5)
    """
    recipe = compile_valuascript(script)
    assert recipe is not None

    registry = set(recipe["variable_registry"])
    assert "__calculate_rd_amortization_1__cap_asset" in registry
    assert "__calculate_rd_amortization_1__amortization" in registry
    assert "amortization_value" in registry


def test_udf_calling_another_udf_with_multi_return():
    """
    BUG FIX TEST: Validates that a UDF can call another UDF that
    returns a tuple, using multi-assignment to capture the results.
    This ensures the fix works for nested user-defined function calls.
    """
    script = """
    @iterations=1
    @output=y

    func get_coords() -> (scalar, scalar) {
        return (100, 200)
    }

    func process_coords() -> scalar {
        let x_coord, y_coord = get_coords()
        return y_coord - x_coord
    }

    let y = process_coords()
    """
    recipe = compile_valuascript(script)
    assert recipe is not None

    registry = set(recipe["variable_registry"])
    assert "__process_coords_1__x_coord" in registry
    assert "__process_coords_1__y_coord" in registry
    assert "y" in registry


def test_end_to_end_udf_with_multi_assignment_integration(find_engine_path):
    """
    END-TO-END VALIDATION: Compiles a script with the fixed UDF logic,
    executes it with the C++ engine, and verifies the final computed value.
    This confirms the generated bytecode is correct and the entire toolchain works.
    """
    script = """
    @iterations=1
    @output=final_result

    func calculate_asset_and_return_value(current: scalar, past: vector, life: scalar) -> scalar {
        let capitalized_asset, current_amortization = capitalize_expense(current, past, life)
        # Perform some arbitrary calculation with one of the results
        return capitalized_asset - current_amortization
    }

    let past_expenses = [90, 80, 70]
    let final_result = calculate_asset_and_return_value(100, past_expenses, 3)
    """

    result = run_preview_integration(script, "final_result", find_engine_path)

    assert result.get("status") == "success"
    assert result.get("type") == "scalar"
    assert pytest.approx(result.get("value"), abs=1e-2) == 106.67
