"""Tests for the Mira runtime loader."""

from __future__ import annotations

import importlib
import os
import sys

import pytest
from mira.builder.builder import MiraBuilder
from mira.library.library import MiraLibrary
from mira.library.repository import MiraRepository
from mira.runtime.runtime import MiraRuntime
from tests.helpers import temporary_directory


def _create_project(base_dir: str, entry_point: str | None = "engine.main:run") -> str:
    project_dir = os.path.join(base_dir, "sample_project")
    os.makedirs(project_dir, exist_ok=True)

    tool_mira = ['[tool.mira]', 'include = "engine"']
    if entry_point:
        tool_mira.append(f'entry_point = "{entry_point}"')

    pyproject = "\n".join(
        [
            "[project]",
            'name = "my_engine"',
            'version = "1.0.0"',
            'description = "My awesome engine"',
            "dependencies = []",
            "",
            *tool_mira,
        ]
    )

    with open(
        os.path.join(project_dir, "pyproject.toml"), "w", encoding="utf-8"
    ) as handle:
        handle.write(pyproject.strip())

    engine_dir = os.path.join(project_dir, "engine")
    os.makedirs(engine_dir, exist_ok=True)

    with open(os.path.join(engine_dir, "__init__.py"), "w", encoding="utf-8") as handle:
        handle.write("VALUE = 7\n")

    with open(os.path.join(engine_dir, "core.py"), "w", encoding="utf-8") as handle:
        handle.write("def answer():\n    return 7\n")

    with open(os.path.join(engine_dir, "main.py"), "w", encoding="utf-8") as handle:
        handle.write("def run():\n    return 'ok'\n")

    return project_dir


def test_runtime_load_and_unload() -> None:
    with temporary_directory() as tmp:
        project_dir = _create_project(tmp)
        builder = MiraBuilder(project_dir, output_dir="dist")
        mira_path = builder.build()

        runtime = MiraRuntime()
        runtime.load(mira_path)

        engine = importlib.import_module("engine")
        assert engine.VALUE == 7

        core = importlib.import_module("engine.core")
        assert core.answer() == 7

        runtime.unload("my_engine")

        assert "engine" not in sys.modules


def test_runtime_load_from_repo() -> None:
    with temporary_directory() as tmp:
        project_dir = _create_project(tmp)
        builder = MiraBuilder(project_dir, output_dir="dist")
        mira_path = builder.build()

        repo_dir = os.path.join(tmp, "repo")
        repository = MiraRepository(base_dir=repo_dir)
        library = MiraLibrary(repository=repository)
        library.install(mira_path)

        runtime = MiraRuntime()
        runtime.load_from_repo("my_engine", repository=repository)

        engine = importlib.import_module("engine")
        assert engine.VALUE == 7

        runtime.unload("my_engine")


def test_runtime_run_entry_point() -> None:
    with temporary_directory() as tmp:
        project_dir = _create_project(tmp)
        builder = MiraBuilder(project_dir, output_dir="dist")
        mira_path = builder.build()

        runtime = MiraRuntime()
        result = runtime.run(mira_path)

        assert result == "ok"
        runtime.unload("my_engine")


def test_runtime_run_library_raises() -> None:
    with temporary_directory() as tmp:
        project_dir = _create_project(tmp, entry_point=None)
        builder = MiraBuilder(project_dir, output_dir="dist")
        mira_path = builder.build()

        runtime = MiraRuntime()
        with pytest.raises(RuntimeError, match="entry_point"):
            runtime.run(mira_path)
