"""Tests for scaffold task type."""

from milco.core.run_context import RunContext
from milco.core.artifacts import write_artifact
from milco.tasks.registry import get_task

import milco.tasks.scaffold_task  # noqa: F401


def _make_ctx(tmp_path, contract_body: str, task_type: str = "scaffold"):
    contract = tmp_path / "TASK_CONTRACT.md"
    contract.write_text(contract_body, encoding="utf-8")
    ctx = RunContext(
        repo_root=tmp_path,
        run_id="test-scaffold",
        apply_mode=False,
        contract_path=str(contract),
        task_type=task_type,
    )
    write_artifact(ctx, "evidence.md", "# Evidence\n\nPresent.\n")
    write_artifact(ctx, "task_contract.md", contract_body)
    return ctx


CONTRACT_SCAFFOLD_PYTHON = """\
# Task Contract

## Task Type

scaffold

## Goal

Create module.

## Scaffold

template: python_module
target: src/foo.py
module_name: foo
docstring: Foo module.

## Scope

One file.

## Out of scope

Nothing.

## Success Criteria

Done.

## Constraints

None.

## Approvals required

CONFIRM APPLY

## Notes

None.
"""


def test_scaffold_registered():
    cls = get_task("scaffold")
    assert cls is not None
    assert cls.needs_llm is False
    assert (
        "scaffold" in cls.description.lower() or "template" in cls.description.lower()
    )


def test_scaffold_blocked_without_evidence(tmp_path):
    ctx = _make_ctx(tmp_path, CONTRACT_SCAFFOLD_PYTHON)
    ctx.artifact_path("evidence.md").unlink(missing_ok=True)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is False
    assert any("evidence" in e.lower() for e in result.errors)


def test_scaffold_missing_section_returns_errors(tmp_path):
    contract_no_scaffold = """\
# Task Contract

## Task Type

scaffold

## Goal

Create module.

## Scope

One file.

## Out of scope

Nothing.

## Success Criteria

Done.

## Constraints

None.

## Approvals required

CONFIRM APPLY

## Notes

None.
"""
    ctx = _make_ctx(tmp_path, contract_no_scaffold)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is False
    assert any("Scaffold" in e for e in result.errors)


def test_scaffold_unknown_template_returns_errors(tmp_path):
    contract_bad_template = (
        CONTRACT_SCAFFOLD_PYTHON.replace(
            "template: python_module",
            "template: unknown_template",
        )
        .replace("target: src/foo.py", "target: src/bar.py")
        .replace("module_name: foo", "module_name: bar")
    )
    ctx = _make_ctx(tmp_path, contract_bad_template)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is False
    assert any(
        "Unknown template" in e or "unknown_template" in e for e in result.errors
    )


def test_scaffold_dry_run_produces_diff_and_no_file(tmp_path):
    ctx = _make_ctx(tmp_path, CONTRACT_SCAFFOLD_PYTHON)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is True
    assert result.applied is False
    diff_path = ctx.artifact_path("patches.diff")
    assert diff_path.exists()
    diff_text = diff_path.read_text(encoding="utf-8")
    assert "src/foo.py" in diff_text or "foo" in diff_text
    assert "a/src/foo.py" in diff_text or "b/src/foo.py" in diff_text
    target = tmp_path / "src" / "foo.py"
    assert not target.exists()


def test_scaffold_apply_writes_file(tmp_path):
    contract = CONTRACT_SCAFFOLD_PYTHON + "\nCONFIRM APPLY\n"
    ctx = _make_ctx(tmp_path, contract)
    ctx.apply_mode = True
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is True
    assert result.applied is True
    target = tmp_path / "src" / "foo.py"
    assert target.exists()
    content = target.read_text(encoding="utf-8")
    assert "Foo module." in content
    assert "def main()" in content
    assert "foo" in content


def test_scaffold_pytest_file_template(tmp_path):
    contract = """\
# Task Contract

## Task Type

scaffold

## Goal

Create test file.

## Scaffold

template: pytest_file
target: tests/test_baz.py
module_name: baz

## Scope

One file.

## Out of scope

Nothing.

## Success Criteria

Done.

## Constraints

None.

## Approvals required

CONFIRM APPLY

## Notes

None.
"""
    ctx = _make_ctx(tmp_path, contract)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is True
    diff_text = ctx.artifact_path("patches.diff").read_text(encoding="utf-8")
    assert "test_baz" in diff_text or "baz" in diff_text
    # Apply and check content
    ctx.apply_mode = True
    ctx.contract_path = str(tmp_path / "TASK_CONTRACT.md")
    write_artifact(ctx, "task_contract.md", contract)
    result2 = get_task("scaffold")().fix(ctx)
    assert result2.success is True
    test_file = tmp_path / "tests" / "test_baz.py"
    assert test_file.exists()
    assert "test_baz_placeholder" in test_file.read_text(encoding="utf-8")


def test_scaffold_package_init_template(tmp_path):
    contract = """\
# Task Contract

## Task Type

scaffold

## Goal

Create package __init__.py.

## Scaffold

template: package_init
target: mypkg/__init__.py
docstring: My package.
exports: foo, bar

## Scope

One file.

## Out of scope

Nothing.

## Success Criteria

Done.

## Constraints

None.

## Approvals required

CONFIRM APPLY

## Notes

None.
"""
    ctx = _make_ctx(tmp_path, contract)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is True
    diff_text = ctx.artifact_path("patches.diff").read_text(encoding="utf-8")
    assert "__all__" in diff_text or "mypkg" in diff_text
    ctx.apply_mode = True
    write_artifact(ctx, "task_contract.md", contract)
    result2 = get_task("scaffold")().fix(ctx)
    assert result2.success is True
    init_file = tmp_path / "mypkg" / "__init__.py"
    assert init_file.exists()
    content = init_file.read_text(encoding="utf-8")
    assert "My package." in content
    assert "__all__" in content
    assert '"foo"' in content and '"bar"' in content


def test_scaffold_script_template(tmp_path):
    contract = """\
# Task Contract

## Task Type

scaffold

## Goal

Create CLI script.

## Scaffold

template: script
target: scripts/tool.py
module_name: tool
description: My CLI tool.
docstring: CLI entry point.

## Scope

One file.

## Out of scope

Nothing.

## Success Criteria

Done.

## Constraints

None.

## Approvals required

CONFIRM APPLY

## Notes

None.
"""
    ctx = _make_ctx(tmp_path, contract)
    task = get_task("scaffold")()
    result = task.fix(ctx)
    assert result.success is True
    diff_text = ctx.artifact_path("patches.diff").read_text(encoding="utf-8")
    assert "argparse" in diff_text or "tool" in diff_text
    ctx.apply_mode = True
    write_artifact(ctx, "task_contract.md", contract)
    result2 = get_task("scaffold")().fix(ctx)
    assert result2.success is True
    script_file = tmp_path / "scripts" / "tool.py"
    assert script_file.exists()
    content = script_file.read_text(encoding="utf-8")
    assert "argparse" in content
    assert "main()" in content
    assert "tool" in content
    assert "My CLI tool" in content or "CLI entry point" in content
