from __future__ import annotations

import json
from pathlib import Path

import pytest

from aura import paths as aura_paths
from aura.drones.definition import DroneDefinition
from aura.drones.receipt import DroneReceipt
from aura.drones.runner import DroneRunner
from aura.drones.store import DroneStore


@pytest.fixture(autouse=True)
def _patch_data_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(aura_paths, "data_dir", lambda: tmp_path / "data")
    monkeypatch.setattr("aura.drones.store.data_dir", lambda: tmp_path / "data")


def _register_folder_drone(workspace: Path) -> DroneDefinition:
    folder = workspace / "build" / "runner-drone"
    folder.mkdir(parents=True)
    (folder / "main.py").write_text(
        "def run(payload):\n"
        "    return {'message': 'ran', 'goal': payload.get('goal')}\n",
        encoding="utf-8",
    )
    (folder / "smoke.py").write_text(
        "def run(payload):\n"
        "    return {'ok': True}\n",
        encoding="utf-8",
    )
    (folder / "drone.json").write_text(
        json.dumps(
            {
                "id": "runner-drone",
                "name": "Runner Drone",
                "description": "Run this goal.",
                "runtime": "python",
                "entrypoint": "main:run",
                "smoke": "smoke:run",
                "instructions": "Run.",
                "write_policy": "read_only",
                "output_contract": "Return cargo.",
            }
        ),
        encoding="utf-8",
    )
    return DroneStore.register_drone_folder(workspace, folder)


def test_drone_runner_executes_folder_entrypoint(tmp_path: Path) -> None:
    drone = _register_folder_drone(tmp_path)
    runner = DroneRunner(tmp_path, drone)
    statuses: list[str] = []
    chunks: list[str] = []
    receipts: list[DroneReceipt] = []

    runner.statusChanged.connect(statuses.append)
    runner.contentDelta.connect(chunks.append)
    runner.receiptReady.connect(receipts.append)

    runner.run()

    assert statuses[-1] == "completed"
    assert "ran" in "".join(chunks)
    assert len(receipts) == 1
    assert receipts[0].status == "completed"
    assert receipts[0].produced_artifact == {
        "message": "ran",
        "goal": "Run this goal.",
    }


def test_drone_runner_rejects_non_folder_drone(tmp_path: Path) -> None:
    drone = DroneDefinition(
        id="old",
        name="Old",
        description="Old",
        instructions="Use tools.",
        write_policy="read_only",
        output_contract="Summary.",
    )
    runner = DroneRunner(tmp_path, drone)
    errors: list[tuple[int, str]] = []
    receipts: list[DroneReceipt] = []

    runner.apiError.connect(lambda code, message: errors.append((code, message)))
    runner.receiptReady.connect(receipts.append)

    runner.run()

    assert errors
    assert "folder-backed" in errors[0][1]
    assert receipts[0].status == "failed"
