import random
from pathlib import Path

from mixersystem.data.repository import (
    context_scope, get_context, parse_result,
    update_session_run,
)
from mixersystem.workflows.shared import artifact_builder as builder
from mixersystem.workflows.work.agents import work_tester as tester
from mixersystem.workflows.shared.implementation_checker import run as check_implementation

DEFAULT_MAX_TEST_ITERATIONS = 5
_CONCRETE_PROVIDERS = ["claude", "gemini", "codex"]
_SUPPORTED_PROVIDERS = {*_CONCRETE_PROVIDERS, "random"}


def _resolve_provider(provider: str) -> str:
    """Resolve provider name, picking randomly if 'random'."""
    if provider == "random":
        return random.choice(_CONCRETE_PROVIDERS)
    return provider



async def run(session_folder: str, lite: bool = False,
              depth: int | None = None,
              work_builder_provider: str = "claude",
              max_test_iterations: int = DEFAULT_MAX_TEST_ITERATIONS,
              instructions: str | None = None,
              use_questions: bool = True) -> None:
    """Build code from plan.md using build/test loop until pass or max iterations."""
    if max_test_iterations < 0:
        raise ValueError("max_test_iterations must be >= 0")
    if work_builder_provider not in _SUPPORTED_PROVIDERS:
        allowed = ", ".join(sorted(_SUPPORTED_PROVIDERS))
        raise ValueError(
            f"Unsupported work_builder_provider: {work_builder_provider}. "
            f"Supported providers: {allowed}."
        )

    resolved_provider = _resolve_provider(work_builder_provider)

    wf = Path(session_folder)
    wf.mkdir(parents=True, exist_ok=True)

    with context_scope(
        session_folder=str(wf.resolve()),
        lite=lite,
        depth=depth,
    ):
        await _build_and_test(
            provider=resolved_provider,
            max_test_iterations=max_test_iterations,
            instructions=instructions,
            use_questions=use_questions,
        )
        await check_implementation("work")


async def _build_and_test(*, provider: str = "claude",
                          max_test_iterations: int,
                          instructions: str | None = None,
                          use_questions: bool = True) -> None:
    """Run artifact builder + tester loop. Raises if tests never pass."""
    ctx = get_context()

    update_session_run(
        ctx.session_folder, "work",
        provider=provider,
        max_test_iterations=max_test_iterations,
        lite=ctx.lite,
    )

    session_id = await builder.run(
        stage="work",
        provider=provider,
        instructions=instructions,
        use_questions=use_questions,
    )

    # Skip testing entirely when max_test_iterations is 0
    if max_test_iterations == 0:
        return

    # Artifact builder<->tester loop
    passed = False
    last_test_feedback = ""
    test_iterations = 0
    for test_iteration in range(1, max_test_iterations + 1):
        test_iterations = test_iteration
        test_response = await tester.run()
        test_result = parse_result(test_response)
        last_test_feedback = test_result.notes or test_response

        if test_result.passed:
            passed = True
            break

        # Do not run another artifact builder pass after the final allowed failed test.
        if test_iteration < max_test_iterations:
            session_id = await builder.run_resume(
                stage="work",
                feedback=last_test_feedback,
                session_id=session_id,
                provider=provider,
            )

    if not passed:
        raise RuntimeError(
            f"Work build failed: tester still failing after {max_test_iterations} iterations."
        )


if __name__ == "__main__":
    from mixersystem.data.repository import run_cli
    run_cli(run)
