from dataclasses import dataclass
from enum import Enum
from pathlib import Path


class ProjectKind(Enum):
    CMAKE = "cmake"
    MSBUILD = "msbuild"


class ResultCheckKind(Enum):
    CMAKE_COMPILER_IS_MSVC = "cmake_compiler_is_msvc"
    CTEST_HAS_TESTS = "ctest_has_tests"


@dataclass(frozen=True)
class CMakeConfig:
    source_dir: Path
    binary_dir: Path | None = None
    configure_preset: str | None = None
    build_preset: str | None = None
    test_preset: str | None = None


@dataclass(frozen=True)
class MSBuildConfig:
    solution: Path | None = None
    configuration: str = "Debug"
    platform: str = "x64"
    test_command: tuple[str, ...] | None = None


@dataclass(frozen=True)
class TDDConfig:
    test_roots: tuple[Path, ...]
    test_patterns: tuple[str, ...]
    exclude: tuple[str, ...] = ()


@dataclass(frozen=True)
class HarnessConfig:
    version: int
    project_type: str
    cmake: CMakeConfig
    msbuild: MSBuildConfig
    tdd: TDDConfig


@dataclass(frozen=True)
class ProjectSelection:
    kind: ProjectKind
    project_file: Path


@dataclass(frozen=True)
class DiscoveryResult:
    selection: ProjectSelection | None
    cpp_files: tuple[Path, ...] = ()


@dataclass(frozen=True)
class Toolchain:
    installation: Path
    msbuild: Path
    cmake: Path | None = None
    ctest: Path | None = None


@dataclass(frozen=True)
class CommandSpec:
    argv: tuple[str, ...]
    cwd: Path
    stage: str
    timeout_seconds: int = 1800


@dataclass(frozen=True)
class ResultCheck:
    kind: ResultCheckKind
    path: Path | None = None


@dataclass(frozen=True)
class ValidationStep:
    command: CommandSpec
    checks: tuple[ResultCheck, ...] = ()


@dataclass(frozen=True)
class ValidationPlan:
    project_kind: ProjectKind
    steps: tuple[ValidationStep, ...]


@dataclass(frozen=True)
class CommandResult:
    command: CommandSpec
    returncode: int
    stdout: str
    stderr: str
