class TestSettingsApi:
    def test_list_defaults(self, api):
        d = api.get("/settings/list").json()
        keys = {s["key"] for s in d["settings"]}
        for k in ("amount_min", "amount_max", "shipping_min", "shipping_max",
                  "invoice_format", "invoice_prefix", "default_daily_limit",
                  "attachment_kind", "unsubscribe_enabled", "company_name"):
            assert k in keys
        assert all(s["is_default"] for s in d["settings"])
        s0 = d["settings"][0]
        assert {"key", "label", "category", "type", "value", "default"} <= set(s0)

    def test_save_and_persist(self, api):
        r = api.post("/settings/save", headers=H(api),
                     json={"key": "amount_min", "value": 25.5})
        assert r.status_code == 200, r.text
        assert r.json()["value"] == 25.5
        row = [s for s in api.get("/settings/list").json()["settings"]
               if s["key"] == "amount_min"][0]
        assert row["value"] == 25.5 and row["is_default"] is False

    def test_save_rejects_out_of_range(self, api):
        r = api.post("/settings/save", headers=H(api),
                     json={"key": "amount_min", "value": -5})
        assert r.status_code == 400
        r2 = api.post("/settings/save", headers=H(api),
                      json={"key": "default_rate_per_minute", "value": 99999})
        assert r2.status_code == 400

    def test_save_rejects_unknown_key(self, api):
        r = api.post("/settings/save", headers=H(api),
                     json={"key": "no_such_setting", "value": 1})
        assert r.status_code == 400

    def test_bool_and_string_coercion(self, api):
        r = api.post("/settings/save", headers=H(api),
                     json={"key": "unsubscribe_enabled", "value": "false"})
        assert r.status_code == 200
        assert r.json()["value"] is False

        r2 = api.post("/settings/save", headers=H(api),
                      json={"key": "company_name", "value": "Acme Corp"})
        assert r2.status_code == 200
        assert r2.json()["value"] == "Acme Corp"

    def test_attachment_kind_whitelist(self, api):
        ok = api.post("/settings/save", headers=H(api),
                      json={"key": "attachment_kind", "value": "order"})
        assert ok.status_code == 200
        bad = api.post("/settings/save", headers=H(api),
                       json={"key": "attachment_kind", "value": "garbage"})
        assert bad.status_code == 400

    def test_invoice_format_requires_tokens(self, api):
        bad = api.post("/settings/save", headers=H(api),
                       json={"key": "invoice_format", "value": "INV-9999"})
        assert bad.status_code == 400
        ok = api.post("/settings/save", headers=H(api),
                      json={"key": "invoice_format", "value": "{prefix}{seq4}"})
        assert ok.status_code == 200

    def test_save_batch_partial_errors(self, api):
        r = api.post("/settings/save-batch", headers=H(api),
                     json={"values": {"amount_min": 10, "amount_max": 900,
                                      "bogus_key": 1, "shipping_min": "nope"}})
        assert r.status_code == 200
        d = r.json()
        assert d["applied"] == {"amount_min": 10, "amount_max": 900}
        assert "bogus_key" in d["errors"] and "shipping_min" in d["errors"]

    def test_reset_and_reset_all(self, api):
        api.post("/settings/save", headers=H(api), json={"key": "amount_min", "value": 77})
        api.post("/settings/save", headers=H(api), json={"key": "amount_max", "value": 888})
        r = api.post("/settings/reset", headers=H(api), json={"key": "amount_min"})
        assert r.status_code == 200
        row = [s for s in api.get("/settings/list").json()["settings"]
               if s["key"] == "amount_min"][0]
        assert row["is_default"] is True
        r2 = api.post("/settings/reset-all", headers=H(api))
        assert r2.status_code == 200 and r2.json()["reset"] == 1  # only amount_max left

    def test_requires_auth(self, api):
        from starlette.testclient import TestClient
        anon = TestClient(api.app)
        assert anon.get("/settings/list").status_code == 401
        r = anon.post("/settings/save", json={"key": "amount_min", "value": 1})
        assert r.status_code == 401

    def test_csrf_required(self, api):
        r = api.post("/settings/save", json={"key": "amount_min", "value": 5})
        assert r.status_code == 403


# ---------------------------------------------------------------------------
# Logs (send attempts, events, audit, DLQ, export)
# ---------------------------------------------------------------------------
class TestLogsApi:
