from __future__ import annotations

import json

import pytest

from recoil.execution.providers.flora_projects import _projects_path
from recoil.pipeline.tools import archive_flora_junk_drawer as archive


PROJECT = "fixture"


@pytest.fixture
def project_root(tmp_path, monkeypatch):
    root = tmp_path / "projects"
    root.mkdir()
    (root / ".recoil-data-root").touch()
    project = root / PROJECT
    project.mkdir()
    monkeypatch.setenv("RECOIL_PROJECTS_ROOT", str(root))
    monkeypatch.setenv("RECOIL_FLORA_PROJECT", "prj_legacy")
    monkeypatch.setenv("FLORA_API_KEY", "ak_test")
    return project


class _Resp:
    def __init__(self, status_code=200, body=None, text=""):
        self.status_code = status_code
        self._body = body if body is not None else {}
        self.text = text

    def json(self):
        return self._body


def _mock_get(calls, *, fail=False):
    def _get(url, headers=None, timeout=30):
        calls.append({"method": "GET", "url": url, "headers": headers, "timeout": timeout})
        assert headers["User-Agent"] == "recoil-pipeline/1.0"
        assert headers["Authorization"] == "Bearer ak_test"
        if fail:
            return _Resp(500, {"error": "boom"}, "boom")
        if url.endswith("/nodes"):
            return _Resp(
                body={
                    "nodes": [
                        {
                            "node_id": "node_1",
                            "type": "image",
                            "asset_id": "asset_1",
                            "url": "https://cdn.example/a.png",
                            "label": "panel",
                            "width": 1024,
                            "height": 768,
                            "raw_graph": {"secret": True},
                        },
                        {"node_id": "node_2", "type": "video"},
                    ]
                }
            )
        return _Resp(body={"project_id": "prj_legacy", "name": "legacy"})

    return _get


def test_dry_run_prints_inventory_and_writes_nothing(project_root, monkeypatch, capsys):
    calls = []
    monkeypatch.setattr(archive.requests, "get", _mock_get(calls))

    assert archive.main(["--project", PROJECT, "--dry-run"]) == 0

    output = json.loads(capsys.readouterr().out)
    assert output["dry_run"] is True
    assert output["project_id"] == "prj_legacy"
    assert output["node_count"] == 2
    assert not (project_root / "_history").exists()
    assert not _projects_path(PROJECT).exists()
    assert [call["method"] for call in calls] == ["GET", "GET"]
    assert "DELETE" not in {call["method"] for call in calls}


def test_receipt_and_tombstone_written_on_success(project_root, monkeypatch, capsys):
    calls = []
    monkeypatch.setattr(archive.requests, "get", _mock_get(calls))

    assert archive.main(["--project", PROJECT]) == 0

    output = json.loads(capsys.readouterr().out)
    receipt = project_root / output["receipt"]
    assert receipt.exists()

    data = json.loads(receipt.read_text(encoding="utf-8"))
    assert data["project_id"] == "prj_legacy"
    assert data["node_count"] == 2
    assert data["reason"] == "per-episode projects supersede shared scratch (SYNTHESIS d.19)"
    assert data["nodes"][0] == {
        "node_id": "node_1",
        "type": "image",
        "asset_id": "asset_1",
        "url": "https://cdn.example/a.png",
        "label": "panel",
        "width": 1024,
        "height": 768,
    }
    assert "raw_graph" not in data["nodes"][0]

    mapping = json.loads(_projects_path(PROJECT).read_text(encoding="utf-8"))
    assert mapping["_legacy_shared"]["project_id"] == "prj_legacy"
    assert mapping["_legacy_shared"]["receipt"] == f"_history/archives/{receipt.name}"
    assert "tombstoned_at" in mapping["_legacy_shared"]
    assert "DELETE" not in {call["method"] for call in calls}


def test_http_failure_exits_one_and_writes_no_receipt(project_root, monkeypatch, capsys):
    calls = []
    monkeypatch.setattr(archive.requests, "get", _mock_get(calls, fail=True))

    assert archive.main(["--project", PROJECT]) == 1

    captured = capsys.readouterr()
    assert "HTTP 500" in captured.err
    assert not (project_root / "_history").exists()
    assert not _projects_path(PROJECT).exists()
    assert [call["method"] for call in calls] == ["GET"]
    assert "DELETE" not in {call["method"] for call in calls}
