import os

import pytest
from fastapi.testclient import TestClient


@pytest.fixture
def client(tmp_path, monkeypatch):
    db = tmp_path / "t.sqlite3"
    monkeypatch.setenv("GOODNEWS_DB", str(db))
    # http base → cookies aren't Secure-only, so the TestClient round-trips them
    monkeypatch.setenv("GOODNEWS_PUBLIC_BASE_URL", "http://testserver")
    import importlib
    import goodnews.api as api
    importlib.reload(api)
    from goodnews.db import connect, init_db
    c = connect(str(db)); init_db(c); c.close()
    return api.create_app(), api


def test_magic_link_end_to_end(client, monkeypatch):
    app, api = client
    sent = {}
    # capture the link instead of sending real email
    monkeypatch.setattr(api.email_send, "send_magic_link", lambda to, link: sent.update(to=to, link=link))
    tc = TestClient(app)

    # not signed in
    assert tc.get("/api/auth/me").json() is None

    # request a link
    r = tc.post("/api/auth/email/start", json={"email": "Jay@Example.com"})
    assert r.status_code == 200 and r.json() == {"ok": True}
    assert sent["to"] == "jay@example.com"
    token = sent["link"].split("token=")[1]

    # verify → session established (cookie set), user created
    r = tc.post("/api/auth/email/verify", json={"token": token})
    assert r.status_code == 200
    body = r.json()
    assert body["user"]["email"] == "jay@example.com" and body["token"]

    # cookie now authenticates /me
    me = tc.get("/api/auth/me").json()
    assert me and me["email"] == "jay@example.com"

    # bearer token also works (app clients)
    bare = TestClient(app)
    me2 = bare.get("/api/auth/me", headers={"Authorization": f"Bearer {body['token']}"}).json()
    assert me2["email"] == "jay@example.com"

    # reusing the magic link fails (single use)
    assert tc.post("/api/auth/email/verify", json={"token": token}).status_code == 400

    # logout clears the session
    assert tc.post("/api/auth/logout").json() == {"ok": True}
    assert tc.get("/api/auth/me").json() is None


def test_start_rejects_bad_email(client):
    app, _ = client
    tc = TestClient(app)
    assert tc.post("/api/auth/email/start", json={"email": "nope"}).status_code == 422


def test_verify_bad_token(client):
    app, _ = client
    tc = TestClient(app)
    assert tc.post("/api/auth/email/verify", json={"token": "garbage"}).status_code == 400
