from pathlib import Path

from ..models import (
    CommandSpec,
    HarnessConfig,
    ProjectKind,
    ProjectSelection,
    ResultCheck,
    ResultCheckKind,
    Toolchain,
    ValidationPlan,
    ValidationStep,
)
from .base import AdapterError


class CMakeAdapter:
    def create_plan(
        self,
        root: Path,
        selection: ProjectSelection,
        config: HarnessConfig,
        tools: Toolchain,
    ) -> ValidationPlan:
        if selection.kind is not ProjectKind.CMAKE:
            raise AdapterError("CMakeAdapter requires a CMake project selection")
        if tools.cmake is None:
            raise AdapterError("CMake tool is required")
        if tools.ctest is None:
            raise AdapterError("CTest tool is required")

        if config.cmake.configure_preset is None:
            command_cwd = root
            binary = root / ".harness/build"
            configure = (
                str(tools.cmake),
                "-S",
                str(config.cmake.source_dir),
                "-B",
                str(binary),
                "-A",
                "x64",
            )
            build = (str(tools.cmake), "--build", str(binary), "--config", "Debug")
            discover = (
                str(tools.ctest),
                "--test-dir",
                str(binary),
                "-C",
                "Debug",
                "--show-only=json-v1",
            )
            test = (
                str(tools.ctest),
                "--test-dir",
                str(binary),
                "-C",
                "Debug",
                "--output-on-failure",
            )
        else:
            command_cwd = config.cmake.source_dir
            binary = config.cmake.binary_dir
            if (
                binary is None
                or config.cmake.build_preset is None
                or config.cmake.test_preset is None
            ):
                raise AdapterError("CMake presets require binary, build, and test settings")
            configure = (str(tools.cmake), "--preset", config.cmake.configure_preset)
            build = (str(tools.cmake), "--build", "--preset", config.cmake.build_preset)
            discover = (
                str(tools.ctest),
                "--preset",
                config.cmake.test_preset,
                "--show-only=json-v1",
            )
            test = (
                str(tools.ctest),
                "--preset",
                config.cmake.test_preset,
                "--output-on-failure",
            )

        return ValidationPlan(
            ProjectKind.CMAKE,
            (
                ValidationStep(
                    CommandSpec(configure, command_cwd, "configure"),
                    (ResultCheck(ResultCheckKind.CMAKE_COMPILER_IS_MSVC, binary),),
                ),
                ValidationStep(CommandSpec(build, command_cwd, "build")),
                ValidationStep(
                    CommandSpec(discover, command_cwd, "test-discovery"),
                    (ResultCheck(ResultCheckKind.CTEST_HAS_TESTS),),
                ),
                ValidationStep(CommandSpec(test, command_cwd, "test")),
            ),
        )
