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)")
    for aid in (1, 2, 3):
        c.execute("INSERT INTO articles (id,source_id,canonical_url,title,url_hash) "
                  "VALUES (?,1,?,?,?)", (aid, f"http://s/{aid}", f"t{aid}", f"h{aid}"))
    c.commit(); c.close()
    return api.create_app(), api


def _signed_in(app, api):
    """A TestClient with an authenticated session cookie."""
    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"})
        token = sent["link"].split("token=")[1]
        tc.post("/api/auth/email/verify", json={"token": token})
    finally:
        es.send_magic_link = orig
    return tc


def test_saved_requires_auth(client):
    app, _ = client
    assert TestClient(app).get("/api/saved").status_code == 401
    assert TestClient(app).post("/api/saved/1").status_code == 401


def test_save_unsave_and_list(client):
    app, api = client
    tc = _signed_in(app, api)
    assert tc.get("/api/saved/ids").json() == []
    assert tc.post("/api/saved/1").json() == {"saved": True}
    assert tc.post("/api/saved/2").json() == {"saved": True}
    assert tc.post("/api/saved/1").json() == {"saved": True}  # idempotent
    assert sorted(tc.get("/api/saved/ids").json()) == [1, 2]
    body = tc.get("/api/saved").json()
    assert body["count"] == 2 and {a["id"] for a in body["items"]} == {1, 2}
    assert tc.post("/api/saved/999").status_code == 404  # unknown article
    tc.delete("/api/saved/1")
    assert tc.get("/api/saved/ids").json() == [2]


def test_history_and_import(client):
    app, api = client
    tc = _signed_in(app, api)
    tc.post("/api/history", json={"ids": [1, 2, 2, 999]})  # 999 ignored (FK-safe)
    hist = tc.get("/api/history").json()
    assert {a["id"] for a in hist["items"]} == {1, 2}
    # import folds device-local seen + saved (unknown ids dropped)
    tc.post("/api/import", json={"seen": [3], "saved": [1, 999]})
    assert {a["id"] for a in tc.get("/api/history").json()["items"]} == {1, 2, 3}
    assert tc.get("/api/saved/ids").json() == [1]
    # granular removal from history
    tc.delete("/api/history/2")
    assert {a["id"] for a in tc.get("/api/history").json()["items"]} == {1, 3}
    # clear ALL history
    assert tc.delete("/api/history").json() == {"ok": True}
    assert tc.get("/api/history").json()["items"] == []
