"""End-to-end integration tests for the v0.23.0 sign-in state-resume
vertical (§6.2, roadmap item #29).

New behavior: each authenticated user's last-viewed route + a small bag
of light view state is tracked server-side, so the next sign-in can land
them back where they left off rather than on the empty-state home view.

The tests below prove:

  * `PUT /api/me/last-state` requires auth — an anonymous client gets
    401, and nothing is stored.
  * An authenticated PUT upserts the route, and the stored route is
    read back for that user off `GET /api/auth/me` (`last_route`).
  * A second PUT overwrites (upsert, one row per user) — the latest
    route wins.
  * `last_route_state` round-trips as decoded JSON on `/api/auth/me`.
  * Per-user isolation: user A's stored route is not visible to user B.
  * `resume_enabled = 0` disables resume: the PUT no-ops (does not
    rewrite the stored route) and `/api/auth/me` hands back a null
    `last_route` even though a stored row exists.

The fakes from `test_propose_vertical` give us a working app harness +
the `sign_in_as` / `provision_user_row` seams.
"""
from __future__ import annotations

from test_propose_vertical import (  # noqa: F401
    FakeGitea,
    app_with_fake_gitea,
    provision_user_row,
    sign_in_as,
    tmp_env,
)


def test_put_last_state_requires_auth(app_with_fake_gitea):
    from fastapi.testclient import TestClient
    from app import db

    app, _fake = app_with_fake_gitea
    with TestClient(app) as client:
        # Anonymous — no session cookie set.
        r = client.put("/api/me/last-state", json={"route": "/rfc/open-human-model"})
        assert r.status_code == 401
        # Nothing landed in the table.
        row = db.conn().execute("SELECT COUNT(*) AS n FROM user_session_state").fetchone()
        assert row["n"] == 0


def test_put_last_state_upserts_and_reads_back(app_with_fake_gitea):
    from fastapi.testclient import TestClient

    app, _fake = app_with_fake_gitea
    with TestClient(app) as client:
        provision_user_row(user_id=2, login="alice", role="contributor")
        sign_in_as(client, user_id=2, gitea_login="alice", display_name="Alice", role="contributor", email="alice@test")

        # First POST stores a route + light state.
        r = client.put(
            "/api/me/last-state",
            json={"route": "/rfc/open-human-model", "state": {"tab": "discussion", "scroll": 420}},
        )
        assert r.status_code == 200
        assert r.json()["stored"] is True

        # /api/auth/me hands the route + decoded state back.
        me = client.get("/api/auth/me").json()
        assert me["authenticated"] is True
        assert me["user"]["resume_enabled"] is True
        assert me["user"]["last_route"] == "/rfc/open-human-model"
        assert me["user"]["last_route_state"] == {"tab": "discussion", "scroll": 420}

        # A later POST overwrites — one row per user, latest wins.
        r = client.put("/api/me/last-state", json={"route": "/proposals/7"})
        assert r.status_code == 200
        me = client.get("/api/auth/me").json()
        assert me["user"]["last_route"] == "/proposals/7"
        # state was omitted on the second POST → cleared to null.
        assert me["user"]["last_route_state"] is None


def test_last_state_is_per_user(app_with_fake_gitea):
    from fastapi.testclient import TestClient

    app, _fake = app_with_fake_gitea
    with TestClient(app) as client:
        provision_user_row(user_id=2, login="alice", role="contributor")
        provision_user_row(user_id=3, login="bob", role="contributor")

        sign_in_as(client, user_id=2, gitea_login="alice", display_name="Alice", role="contributor", email="alice@test")
        client.put("/api/me/last-state", json={"route": "/rfc/alice-route"})

        # Switch to bob — he has no stored route yet.
        sign_in_as(client, user_id=3, gitea_login="bob", display_name="Bob", role="contributor", email="bob@test")
        me = client.get("/api/auth/me").json()
        assert me["user"]["last_route"] is None

        client.put("/api/me/last-state", json={"route": "/rfc/bob-route"})
        me = client.get("/api/auth/me").json()
        assert me["user"]["last_route"] == "/rfc/bob-route"

        # Back to alice — her route is untouched by bob's write.
        sign_in_as(client, user_id=2, gitea_login="alice", display_name="Alice", role="contributor", email="alice@test")
        me = client.get("/api/auth/me").json()
        assert me["user"]["last_route"] == "/rfc/alice-route"


def test_resume_disabled_no_ops_put_and_hides_route(app_with_fake_gitea):
    from fastapi.testclient import TestClient
    from app import db

    app, _fake = app_with_fake_gitea
    with TestClient(app) as client:
        provision_user_row(user_id=2, login="alice", role="contributor")
        sign_in_as(client, user_id=2, gitea_login="alice", display_name="Alice", role="contributor", email="alice@test")

        # Seed a stored row, then flip resume_enabled off directly (the
        # profile-settings toggle UI to do this from the client is a
        # follow-up; the column + behavior ship now).
        client.put("/api/me/last-state", json={"route": "/rfc/before-disable"})
        db.conn().execute(
            "UPDATE user_session_state SET resume_enabled = 0 WHERE user_id = ?",
            (2,),
        )

        # /api/auth/me reports resume off and hands back a null route
        # even though a stored row exists.
        me = client.get("/api/auth/me").json()
        assert me["user"]["resume_enabled"] is False
        assert me["user"]["last_route"] is None

        # A PUT while disabled no-ops: stored=False and the stored route
        # is NOT rewritten.
        r = client.put("/api/me/last-state", json={"route": "/rfc/after-disable"})
        assert r.status_code == 200
        assert r.json()["stored"] is False
        row = db.conn().execute(
            "SELECT last_route FROM user_session_state WHERE user_id = ?", (2,)
        ).fetchone()
        assert row["last_route"] == "/rfc/before-disable"
