"""The session cookie and sign-in state the app and the wake function share.

These are the pure parts of the sign-in: what a cookie or a ``state`` holds,
and which ones are refused. The call to WorkOS is exercised end to end on a
running playground, not here.
"""

from __future__ import annotations

import base64
import json

from quber.playground import session

SECRET = "test-secret"
ORG = "org_qubera"
NOW = 1_800_000_000.0
IDENTITY = session.Identity(
    user_id="user_1", email="person@example.com", organization_id=ORG, role="member", sid="session_1"
)


def test_a_cookie_checks_back_to_the_identity_it_was_issued_for() -> None:
    token = session.issue(SECRET, IDENTITY, now=NOW)
    assert session.verify(SECRET, ORG, token, now=NOW + 60) == IDENTITY


def test_a_cookie_lives_two_hours() -> None:
    token = session.issue(SECRET, IDENTITY, now=NOW)
    assert session.verify(SECRET, ORG, token, now=NOW + session.SESSION_SECONDS - 1) == IDENTITY
    assert session.verify(SECRET, ORG, token, now=NOW + session.SESSION_SECONDS) is None
    assert session.SESSION_SECONDS == 2 * 3600


def test_a_cookie_signed_with_another_secret_is_refused() -> None:
    token = session.issue("other-secret", IDENTITY, now=NOW)
    assert session.verify(SECRET, ORG, token, now=NOW) is None


def test_a_cookie_for_another_organization_is_refused() -> None:
    token = session.issue(SECRET, IDENTITY, now=NOW)
    assert session.verify(SECRET, "org_someone_else", token, now=NOW) is None


def test_an_edited_cookie_is_refused() -> None:
    token = session.issue(SECRET, IDENTITY, now=NOW)
    body, sig = token.split(".")
    record = json.loads(session.b64decode(body))
    record["organization_id"] = "org_someone_else"
    forged = base64.urlsafe_b64encode(json.dumps(record).encode()).decode().rstrip("=")
    assert session.verify(SECRET, "org_someone_else", f"{forged}.{sig}", now=NOW) is None


def test_malformed_cookies_are_refused() -> None:
    for token in (None, "", "no-dot", "a.b.c", "not-base64!.abc"):
        assert session.verify(SECRET, ORG, token, now=NOW) is None


def test_the_old_cookie_format_is_refused() -> None:
    old = "playground.1900000000.0123456789abcdef"
    assert session.verify(SECRET, ORG, old, now=NOW) is None


def test_sign_out_reads_the_session_id_from_an_expired_cookie() -> None:
    token = session.issue(SECRET, IDENTITY, now=NOW)
    later = NOW + session.SESSION_SECONDS + 3600
    assert session.verify(SECRET, ORG, token, now=later) is None
    found = session.signed_identity(SECRET, token)
    assert found is not None and found.sid == "session_1"
    assert session.signed_identity("other-secret", token) is None


def test_state_returns_the_page_it_was_given() -> None:
    state = session.state_for(SECRET, "/?doc=12", now=NOW)
    assert session.next_from_state(SECRET, state, now=NOW + 60) == "/?doc=12"


def test_state_never_returns_a_page_on_another_site() -> None:
    for target in ("https://evil.example/", "//evil.example/", "/\\evil.example"):
        state = session.state_for(SECRET, target, now=NOW)
        assert session.next_from_state(SECRET, state, now=NOW) == "/"


def test_stale_or_forged_state_is_refused() -> None:
    state = session.state_for(SECRET, "/", now=NOW)
    assert session.next_from_state(SECRET, state, now=NOW + session.STATE_SECONDS) is None
    assert session.next_from_state("other-secret", state, now=NOW) is None


def test_a_state_cannot_stand_in_for_a_cookie_or_the_reverse() -> None:
    state = session.state_for(SECRET, "/", now=NOW)
    token = session.issue(SECRET, IDENTITY, now=NOW)
    assert session.verify(SECRET, ORG, state, now=NOW) is None
    assert session.next_from_state(SECRET, token, now=NOW) is None


def test_a_return_with_bad_state_fails_without_calling_workos() -> None:
    config = session.WorkOS(
        api_key="sk_unused", client_id="client_unused", organization_id=ORG, session_secret=SECRET
    )
    outcome = session.complete_sign_in(
        config, "https://playground.test", "code_1", "forged.state", "/mark.png"
    )
    assert outcome.status == 400 and outcome.token is None
    assert outcome.page is not None and "Sign in again" in outcome.page


def test_the_authorize_url_returns_to_the_host_the_request_came_in_on() -> None:
    config = session.WorkOS(api_key="sk", client_id="client_1", organization_id=ORG, session_secret=SECRET)
    url = session.authorize_url(config, "http://192.168.1.237:8101", "/", now=NOW)
    assert url.startswith("https://api.workos.com/user_management/authorize?")
    assert "redirect_uri=http%3A%2F%2F192.168.1.237%3A8101%2Fcallback" in url
    assert "provider=authkit" in url and "client_id=client_1" in url


def test_the_logout_url_names_the_session_and_the_return() -> None:
    url = session.logout_url("session_1", "https://playground.qubera.ai")
    assert url == (
        "https://api.workos.com/user_management/sessions/logout"
        "?session_id=session_1&return_to=https%3A%2F%2Fplayground.qubera.ai%2F"
    )


def test_the_refusal_page_escapes_the_email_and_offers_a_different_account() -> None:
    page = session.refusal_page("<b>x</b>@example.com", "https://api.workos.com/logout?a=1&b=2", "/mark.png")
    assert "&lt;b&gt;x&lt;/b&gt;@example.com" in page
    assert 'href="https://api.workos.com/logout?a=1&amp;b=2"' in page
    assert "Sign in with a different account" in page


def test_the_login_page_carries_the_preview_tags_and_moves_on_to_workos() -> None:
    config = session.WorkOS(api_key="sk", client_id="client_1", organization_id=ORG, session_secret=SECRET)
    page = session.login_page(config, "https://playground.qubera.ai", "/", "/mark.png")
    assert 'property="og:title"' in page
    assert 'http-equiv="refresh"' in page and "user_management/authorize" in page
