"""First-run setup, login, and the basic frame-visibility permission
gate (require_frame_view/can_view_frame) -- the things every other
endpoint's own permission test implicitly depends on already working."""

from __future__ import annotations

from app.models import Frame

from .conftest import get_csrf_token, link_user, login, make_user


def test_setup_creates_admin_and_claims_migrated_frame(client, db_session):
    resp = client.post("/setup", data={
        "username": "alice", "password": "hunter22", "display_name": "Alice",
    })
    assert resp.status_code == 303
    assert resp.headers["location"] == "/"

    frame = db_session.get(Frame, 1)
    assert frame is not None
    assert frame.owner_user_id is not None
    assert frame.controlled_by_user_id is not None


def test_setup_only_works_once(client):
    resp = client.post("/setup", data={"username": "alice", "password": "hunter22"})
    assert resp.status_code == 303

    resp = client.post("/setup", data={"username": "mallory", "password": "hunter22"})
    assert resp.status_code == 403


def test_login_requires_correct_password(client):
    client.post("/setup", data={"username": "alice", "password": "hunter22"})
    client.cookies.clear()

    resp = client.post("/login", data={"username": "alice", "password": "wrong"})
    assert resp.status_code == 401

    resp = client.post("/login", data={"username": "alice", "password": "hunter22"})
    assert resp.status_code == 303


def test_root_redirects_to_setup_before_any_user_exists(client):
    resp = client.get("/")
    assert resp.status_code == 303
    assert resp.headers["location"] == "/setup"


def test_unauthenticated_request_redirects_to_login_once_a_user_exists(client):
    client.post("/setup", data={"username": "alice", "password": "hunter22"})
    client.cookies.clear()

    resp = client.get("/")
    assert resp.status_code == 303
    assert resp.headers["location"] == "/login"


def test_user_not_linked_to_a_frame_cannot_view_it(client, db_session):
    client.post("/setup", data={"username": "alice", "password": "hunter22"})
    bob = make_user(db_session, "bob")
    db_session.flush()

    client.cookies.clear()
    login(client, "bob")

    resp = client.get("/frames/1")
    assert resp.status_code == 404


def test_linked_user_can_view_but_not_configure_by_default(client, db_session):
    """Being linked grants view access; whether they can also *control*
    (change settings/take the wheel) is a separate, narrower gate --
    require_frame_control, exercised via the permission-boundary tests
    for individual features rather than here."""
    client.post("/setup", data={"username": "alice", "password": "hunter22"})
    bob = make_user(db_session, "bob")
    frame = db_session.get(Frame, 1)
    link_user(db_session, bob, frame)

    client.cookies.clear()
    login(client, "bob")

    resp = client.get("/frames/1")
    assert resp.status_code == 200


def test_csrf_token_required_for_settings_save(client):
    client.post("/setup", data={"username": "alice", "password": "hunter22"})
    resp = client.post("/settings", data={
        "display_name": "Alice", "email": "alice@example.com", "csrf_token": "bogus",
    })
    assert resp.status_code == 403


def test_settings_save_round_trips_with_real_csrf_token(client, db_session):
    client.post("/setup", data={"username": "alice", "password": "hunter22"})
    csrf = get_csrf_token(client, "/settings")
    resp = client.post("/settings", data={
        "display_name": "Alice Smith", "email": "alice@example.com", "csrf_token": csrf,
    })
    assert resp.status_code in (200, 303), resp.text

    from app.models import User
    user = db_session.query(User).filter_by(username="alice").one()
    assert user.display_name == "Alice Smith"
