class TestAccountsApi:

    def test_list_empty(self, api):
        d = api.get("/gmail/accounts").json()
        assert d["accounts"] == [] and d["count"] == 0

    def test_seeded_account_shape(self, api, db):
        aid = _seed_account(db, user_id_of(api))
        d = api.get("/gmail/accounts").json()
        assert d["count"] == 1
        a = d["accounts"][0]
        assert {"id", "email", "status", "sending_method", "daily_limit",
                "campaign_limit", "sends_today", "has_refresh_token",
                "authorized"} <= set(a)
        assert a["id"] == aid and a["authorized"] is True
        assert a["has_refresh_token"] is True

    def test_patch_updates_limits_and_method(self, api, db):
        aid = _seed_account(db, user_id_of(api), method="api")
        r = api.patch(f"/gmail/accounts/{aid}", headers=H(api),
                      json={"sending_method": "smtp", "daily_limit": 50,
                            "campaign_limit": 25})
        assert r.status_code == 200, r.text
        d = r.json()
        assert d["sending_method"] == "smtp"
        assert d["daily_limit"] == 50 and d["campaign_limit"] == 25

    def test_patch_404_unknown(self, api):
        r = api.patch("/gmail/accounts/999", headers=H(api),
                      json={"sending_method": "api", "daily_limit": 5,
                            "campaign_limit": 5})
        assert r.status_code == 404

    def test_connect_without_config_is_honest_400(self, api):
        r = api.post("/gmail/accounts/connect", headers=H(api))
        assert r.status_code == 400
        assert "client configuration" in r.text.lower()

    def test_reauthorize_without_config_400(self, api, db):
        aid = _seed_account(db, user_id_of(api))
        r = api.post(f"/gmail/accounts/{aid}/reauthorize", headers=H(api))
        assert r.status_code == 400

    def test_revoke_and_delete_account(self, api, db):
        aid = _seed_account(db, user_id_of(api))
        r = api.post(f"/gmail/accounts/{aid}/revoke", headers=H(api))
        assert r.status_code == 200, r.text
        d = r.json()
        assert d["ok"] is True and "revoked_at_google" in d
        # revoked → is_active False, status revoked, token deleted
        d2 = api.get("/gmail/accounts").json()
        assert d2["accounts"][0]["status"] == "revoked"
        assert d2["accounts"][0]["authorized"] is False
        from app.models import OAuthToken
        assert db.query(OAuthToken).count() == 0
        # DELETE removes the row entirely
        r3 = api.delete(f"/gmail/accounts/{aid}", headers=H(api))
        assert r3.status_code == 200
        assert api.get("/gmail/accounts").json()["count"] == 0

    def test_revoke_deletes_token_row_and_sets_flags(self, api, db):
        aid = _seed_account(db, user_id_of(api))
        api.post(f"/gmail/accounts/{aid}/revoke", headers=H(api))
        from app.models import GmailAccount
        acc = db.get(GmailAccount, aid)
        assert acc.status == "revoked" and acc.is_active is False
        assert acc.revoked_by_user is True and acc.revoked_at is not None

    def test_clear_all(self, api, db):
        _seed_account(db, user_id_of(api), email="a1@x.com")
        _seed_account(db, user_id_of(api), email="a2@x.com")
        r = api.post("/gmail/accounts/clear-all", headers=H(api))
        assert r.status_code == 200
        d = r.json()
        assert d["removed"] == 2
        assert api.get("/gmail/accounts").json()["count"] == 0
        # audit preserved
        acts = api.get("/logs/audit").json()
        assert any(a["action"] == "gmail.clear_all" for a in acts["audit"])

    def test_account_isolation(self, api, db, second_user):
        # second user's account must be invisible and untouchable
        aid = _seed_account(db, user_id_of(api))
        assert second_user.get("/gmail/accounts").json()["accounts"] == []
        r = second_user.patch(f"/gmail/accounts/{aid}", headers=H(second_user),
                              json={"sending_method": "api", "daily_limit": 1,
                                    "campaign_limit": 1})
        assert r.status_code == 404
        r2 = second_user.post(f"/gmail/accounts/{aid}/revoke", headers=H(second_user))
        assert r2.status_code == 404

    def test_import_config_valid_json(self, api):
        cfg = {"installed": {"client_id": "abc-123.apps.googleusercontent.com",
                             "client_secret": "SECRET-XYZ",
                             "project_id": "my-project",
                             "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                             "token_uri": "https://oauth2.googleapis.com/token"}}
        r = api.post("/gmail/accounts/import-config", headers=H(api),
                     files={"file": ("client_secret.json", json.dumps(cfg).encode(),
                                     "application/json")})
        assert r.status_code in (200, 201), r.text
        d = r.json()
        assert d["ok"] is True and d["project_id"] == "my-project"
        # secret is NEVER echoed back, only a preview
        assert "SECRET-XYZ" not in r.text
        assert d["client_id_preview"].startswith("abc-123")
        # after import, connect can build a real authorization URL
        r2 = api.post("/gmail/accounts/connect", headers=H(api))
        assert r2.status_code == 200, r2.text
        assert "accounts.google.com" in r2.json()["authorization_url"]

    def test_import_config_rejects_invalid(self, api):
        r = api.post("/gmail/accounts/import-config", headers=H(api),
                     files={"file": ("bad.json", b'{"nope": true}', "application/json")})
        assert r.status_code == 400
        r2 = api.post("/gmail/accounts/import-config", headers=H(api),
                      files={"file": ("notjson.json", b"not json", "application/json")})
        assert r2.status_code == 400
        r3 = api.post("/gmail/accounts/import-config", headers=H(api),
                      files={"file": ("cfg.txt", b"{}", "text/plain")})
        assert r3.status_code == 400

    def test_requires_auth(self, api):
        from starlette.testclient import TestClient
        anon = TestClient(api.app)
        assert anon.get("/gmail/accounts").status_code == 401
        assert anon.post("/gmail/accounts/clear-all").status_code == 401

    def test_csrf_required_on_mutations(self, api):
        r = api.post("/gmail/accounts/clear-all")
        assert r.status_code == 403
        r2 = api.patch("/gmail/accounts/1", json={})
        assert r2.status_code == 403


# --------------------------------------------------------------------------- test-send
