import json

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))
    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.execute("INSERT INTO sources (id,name,feed_url,trust_score) VALUES (1,'S','http://s/f',5)")
    c.execute("INSERT INTO articles (id,source_id,canonical_url,title,url_hash) VALUES (1,1,'http://s/1','t1','h1')")
    c.commit(); c.close()
    return api.create_app(), api


def _signed_in(app, api):
    tc = TestClient(app)
    sent = {}
    import goodnews.email_send as es
    orig = es.send_magic_link
    es.send_magic_link = lambda to, link: sent.update(link=link)
    try:
        tc.post("/api/auth/email/start", json={"email": "a@b.com"})
        tc.post("/api/auth/email/verify", json={"token": sent["link"].split("token=")[1]})
    finally:
        es.send_magic_link = orig
    return tc


def test_prefs_roundtrip(client):
    app, api = client
    tc = _signed_in(app, api)
    assert tc.get("/api/prefs").json() == {"prefs": None}  # nothing yet → seed from device
    tc.put("/api/prefs", json={"prefs": {"mute_topics": ["health"], "avoid_terms": ["war"]}})
    assert tc.get("/api/prefs").json()["prefs"]["mute_topics"] == ["health"]


def test_account_info_and_export(client):
    app, api = client
    tc = _signed_in(app, api)
    tc.post("/api/saved/1")
    info = tc.get("/api/account").json()
    assert info["user"]["email"] == "a@b.com"
    assert info["providers"] == ["email"] and info["sessions"] >= 1 and info["saved_count"] == 1
    exp = tc.get("/api/account/export")
    assert exp.headers["content-disposition"].endswith("upbeatbytes-data.json")
    data = json.loads(exp.content)
    assert data["account"]["email"] == "a@b.com" and {a["id"] for a in data["saved"]} == {1}


def test_logout_all_and_delete(client):
    app, api = client
    tc = _signed_in(app, api)
    tc.post("/api/saved/1")
    assert tc.post("/api/account/logout-all").json() == {"ok": True}
    assert tc.get("/api/auth/me").json() is None  # session revoked

    tc2 = _signed_in(app, api)  # same email → same account, has the save
    assert tc2.get("/api/saved/ids").json() == [1]
    assert tc2.delete("/api/account").json() == {"ok": True}
    assert tc2.get("/api/auth/me").json() is None
    # a fresh sign-in is a brand-new account (old data gone)
    tc3 = _signed_in(app, api)
    assert tc3.get("/api/saved/ids").json() == []
