from collections import defaultdict
from pathlib import Path

from harbor.cli.analyze.backend import query_agent
from harbor.cli.analyze.models import (
    QualityCheckResult,
    build_check_response_model,
    build_criteria_guidance,
    load_rubric,
)
from harbor.models.task.paths import TaskPaths

PROMPTS_DIR = Path(__file__).parent / "prompts"


async def run_check(
    task_dir: Path,
    model: str = "sonnet",
    rubric_path: Path | None = None,
    prompt_path: Path | None = None,
    verbose: bool = False,
) -> QualityCheckResult:
    """Run quality check on a task directory."""
    task_dir = Path(task_dir)
    if not task_dir.exists() or not task_dir.is_dir():
        raise FileNotFoundError(
            f"Task directory '{task_dir}' not found or is not a directory"
        )

    task_paths = TaskPaths(task_dir)
    if not task_paths.is_valid():
        raise ValueError(
            f"'{task_dir}' is not a valid task directory "
            f"(missing instruction.md, task.toml, or tests/). "
            f"For trial analysis, use 'harbor analyze <trial-dir>' instead."
        )

    rubric = load_rubric(rubric_path)
    response_model = build_check_response_model(rubric)

    template = (
        prompt_path.read_text()
        if prompt_path
        else (PROMPTS_DIR / "check.txt").read_text()
    )
    prompt = template.format_map(
        defaultdict(
            str,
            file_tree=_build_file_tree(task_dir),
            criteria_guidance=build_criteria_guidance(rubric),
        )
    )

    result = await query_agent(
        prompt=prompt,
        model=model,
        cwd=str(task_dir),
        tools=["Read", "Glob", "Grep"],
        output_schema=response_model.model_json_schema(),
        verbose=verbose,
    )

    parsed = response_model.model_validate(result)
    return QualityCheckResult(checks=parsed.model_dump())


def _build_file_tree(task_dir: Path) -> str:
    lines = []
    for path in sorted(task_dir.rglob("*")):
        if not path.is_file():
            continue
        lines.append(path.relative_to(task_dir).as_posix())
    return "\n".join(lines) if lines else "No files found"
