"""Sprint 4 — done read-only + Reopen tests (AC-18)."""
from __future__ import annotations

import pytest
from flask.testing import FlaskClient

from backend.tests.conftest import auth_headers as _h


def _make_engagement(client: FlaskClient, token: str) -> dict:
    resp = client.post(
        "/api/engagements",
        headers=_h(token),
        json={"name": "Eng", "start_date": "2026-01-01"},
    )
    assert resp.status_code == 201
    return resp.get_json()


def _make_sim(client: FlaskClient, token: str, eid: int) -> dict:
    resp = client.post(
        f"/api/engagements/{eid}/simulations",
        headers=_h(token),
        json={"name": "Sim"},
    )
    assert resp.status_code == 201
    return resp.get_json()


def _advance_to_done(client: FlaskClient, redteam_token: str, soc_token: str, sid: int) -> None:
    client.post(
        f"/api/simulations/{sid}/transition",
        headers=_h(redteam_token),
        json={"to": "review_required"},
    )
    client.post(
        f"/api/simulations/{sid}/transition",
        headers=_h(soc_token),
        json={"to": "done"},
    )


def _patch(client: FlaskClient, token: str, sid: int, payload: dict):
    return client.patch(
        f"/api/simulations/{sid}",
        headers=_h(token),
        json=payload,
    )


def _transition(client: FlaskClient, token: str, sid: int, to: str):
    return client.post(
        f"/api/simulations/{sid}/transition",
        headers=_h(token),
        json={"to": to},
    )


# ---------------------------------------------------------------------------
# AC-18.1 — PATCH on done → 409 for all roles
# ---------------------------------------------------------------------------


def test_patch_done_sim_admin_returns_409(
    client: FlaskClient, redteam_token: str, soc_token: str, admin_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _patch(client, admin_token, sim["id"], {"name": "renamed"})
    assert resp.status_code == 409
    assert resp.get_json()["error"] == "simulation is done — reopen first"


def test_patch_done_sim_redteam_returns_409(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _patch(client, redteam_token, sim["id"], {"description": "x"})
    assert resp.status_code == 409


def test_patch_done_sim_soc_returns_409(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _patch(client, soc_token, sim["id"], {"soc_comment": "afterthought"})
    assert resp.status_code == 409


# ---------------------------------------------------------------------------
# AC-18.2 — Reopen: done → review_required, all 3 roles
# ---------------------------------------------------------------------------


@pytest.mark.parametrize("role", ["redteam", "soc", "admin"])
def test_reopen_done_sim_allowed_for_all_roles(
    client: FlaskClient,
    redteam_token: str,
    soc_token: str,
    admin_token: str,
    role: str,
) -> None:
    token = {"redteam": redteam_token, "soc": soc_token, "admin": admin_token}[role]
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _transition(client, token, sim["id"], "review_required")
    assert resp.status_code == 200
    assert resp.get_json()["status"] == "review_required"


# ---------------------------------------------------------------------------
# AC-18.3 — Other transitions from done → 409
# ---------------------------------------------------------------------------


def test_transition_done_to_done_rejected(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _transition(client, redteam_token, sim["id"], "done")
    assert resp.status_code == 409


def test_transition_done_to_in_progress_rejected(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _transition(client, redteam_token, sim["id"], "in_progress")
    assert resp.status_code == 409


def test_transition_done_to_pending_rejected(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])

    resp = _transition(client, redteam_token, sim["id"], "pending")
    assert resp.status_code == 409


# ---------------------------------------------------------------------------
# After reopen, PATCH is allowed again
# ---------------------------------------------------------------------------


def test_patch_allowed_after_reopen(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    _advance_to_done(client, redteam_token, soc_token, sim["id"])
    _transition(client, redteam_token, sim["id"], "review_required")

    resp = _patch(client, soc_token, sim["id"], {"soc_comment": "re-reviewed"})
    assert resp.status_code == 200
    assert resp.get_json()["soc_comment"] == "re-reviewed"


# ---------------------------------------------------------------------------
# AC-18.3 — Normal review_required path (pending/in_progress) unchanged
# ---------------------------------------------------------------------------


def test_transition_review_required_from_in_progress_still_needs_redteam(
    client: FlaskClient, redteam_token: str, soc_token: str
) -> None:
    eng = _make_engagement(client, redteam_token)
    sim = _make_sim(client, redteam_token, eng["id"])
    # Auto-advance to in_progress.
    _patch(client, redteam_token, sim["id"], {"description": "active"})

    resp = _transition(client, soc_token, sim["id"], "review_required")
    assert resp.status_code == 403
