"""End-to-end tests for v0.13.0 / roadmap item #11 — cookie / privacy consent.

Covers the §17 endpoints (`GET` / `PUT /api/users/me/cookie-consent`) and
the §14.5 storage contract:

  * GET on a fresh user returns no-choice-yet (recorded_at is None,
    essential=True, analytics=False, other=False).
  * PUT writes a row, stamps recorded_at, and the choice survives.
  * PUT with `analytics=true, other=false` round-trips faithfully.
  * `essential` is permanently true at the API surface — a PUT that
    requests essential=false is still persisted with essential=true.
  * The endpoint requires authentication (401 for anon).
  * A second PUT updates the existing row in place (single row per
    user, recorded_at re-stamps).
  * Choice persists across sign-out / sign-in.
"""
from __future__ import annotations

import pytest

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


def test_get_cookie_consent_fresh_user_has_no_choice(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")

        r = client.get("/api/users/me/cookie-consent")
        assert r.status_code == 200, r.text
        body = r.json()
        assert body["essential"] is True
        assert body["analytics"] is False
        assert body["other"] is False
        assert body["recorded_at"] is None


def test_put_cookie_consent_records_choice(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")

        r = client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": True, "other": False},
        )
        assert r.status_code == 200, r.text
        body = r.json()
        assert body["ok"] is True
        assert body["essential"] is True
        assert body["analytics"] is True
        assert body["other"] is False
        assert body["recorded_at"] is not None

        # Round-trip the read endpoint.
        r = client.get("/api/users/me/cookie-consent")
        body = r.json()
        assert body["essential"] is True
        assert body["analytics"] is True
        assert body["other"] is False
        assert body["recorded_at"] is not None


def test_put_cookie_consent_forces_essential_true(app_with_fake_gitea):
    """§14.5: `essential` is permanently true at the API surface. A
    request that sets it to false is accepted (for symmetry with the
    other two flags) but persisted as true.
    """
    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")

        r = client.put(
            "/api/users/me/cookie-consent",
            json={"essential": False, "analytics": False, "other": False},
        )
        assert r.status_code == 200, r.text
        assert r.json()["essential"] is True

        # Confirm at the schema layer too — the persisted row has essential=1.
        row = db.conn().execute(
            "SELECT essential FROM cookie_consent WHERE user_id = ?",
            (2,),
        ).fetchone()
        assert row["essential"] == 1


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

    app, _fake = app_with_fake_gitea
    with TestClient(app) as client:
        r = client.get("/api/users/me/cookie-consent")
        assert r.status_code == 401, r.text
        r = client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": True, "other": True},
        )
        assert r.status_code == 401, r.text


def test_put_cookie_consent_upserts_in_place(app_with_fake_gitea):
    """A second PUT updates the existing row rather than inserting a new
    one. Verifies the §14.5 single-row-per-user shape.
    """
    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")

        client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": True, "other": False},
        )
        client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": False, "other": True},
        )

        rows = db.conn().execute(
            "SELECT analytics, other_cookies FROM cookie_consent WHERE user_id = ?",
            (2,),
        ).fetchall()
        assert len(rows) == 1
        assert rows[0]["analytics"] == 0
        assert rows[0]["other_cookies"] == 1


def test_cookie_consent_persists_across_sign_out_in(app_with_fake_gitea):
    """§14.5 precedence: the server row survives sign-out / sign-in.
    """
    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")

        client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": True, "other": True},
        )

        # Simulate sign-out by clearing the session cookie.
        client.cookies.clear()

        # Anonymous viewer cannot read.
        r = client.get("/api/users/me/cookie-consent")
        assert r.status_code == 401

        # Sign back in as Alice. The server row is still there.
        sign_in_as(client, user_id=2, gitea_login="alice", display_name="Alice", role="contributor")
        r = client.get("/api/users/me/cookie-consent")
        body = r.json()
        assert body["analytics"] is True
        assert body["other"] is True
        assert body["recorded_at"] is not None


def test_two_users_have_independent_rows(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")
        client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": True, "other": False},
        )

        sign_in_as(client, user_id=3, gitea_login="bob", display_name="Bob", role="contributor")
        client.put(
            "/api/users/me/cookie-consent",
            json={"essential": True, "analytics": False, "other": False},
        )

        # Each user reads their own row.
        r = client.get("/api/users/me/cookie-consent").json()
        assert r["analytics"] is False  # Bob's

        sign_in_as(client, user_id=2, gitea_login="alice", display_name="Alice", role="contributor")
        r = client.get("/api/users/me/cookie-consent").json()
        assert r["analytics"] is True  # Alice's
