"""Multi-école : création, réglages éditables, isolation entre écoles."""
from conftest import SCHOOL, OTHER_SCHOOL, DIRECTOR_PASSWORD


async def test_operator_creates_a_school_with_clean_defaults(client, admin_token):
    h = {"Authorization": f"Bearer {admin_token}"}
    r = await client.post("/api/admin/schools", json={"name": "Collège Saint-Éloi", "director_password": "motdepasse-8"}, headers=h)
    assert r.status_code == 200, r.text
    school = r.json()["school"]
    assert school["id"] == "college-saint-eloi"
    assert school["has_director_password"] is True

    s = (await client.get("/api/admin/settings", headers={**h, "X-School": school["id"]})).json()
    assert s["settings"]["school_name"] == "Collège Saint-Éloi"
    assert s["settings"]["shoot_date"] == ""          # plus aucune date codée en dur
    assert s["settings"]["partner_name"] == ""
    assert s["settings"]["photographer_name"] == ""

    # le directeur peut se connecter avec le mot de passe défini
    r = await client.post("/api/admin/login", json={"password": "motdepasse-8", "school": school["id"]})
    assert r.status_code == 200


async def test_school_slug_conflict_and_short_password(client, admin_token):
    h = {"Authorization": f"Bearer {admin_token}"}
    assert (await client.post("/api/admin/schools", json={"name": "X", "slug": SCHOOL}, headers=h)).status_code == 400
    assert (await client.post("/api/admin/schools", json={"name": "Y", "director_password": "court"}, headers=h)).status_code == 400


async def test_two_schools_with_same_name_get_distinct_ids(client, admin_token):
    h = {"Authorization": f"Bearer {admin_token}"}
    a = (await client.post("/api/admin/schools", json={"name": "Doublon"}, headers=h)).json()["school"]["id"]
    b = (await client.post("/api/admin/schools", json={"name": "Doublon"}, headers=h)).json()["school"]["id"]
    assert a != b


async def test_settings_update_roundtrip(client, admin_headers):
    r = await client.put("/api/admin/settings", json={"settings": {
        "shoot_date": "2027-03-15", "closure_date": "2027-04-01", "revenue_share_pct": "12.5",
        "partner_name": "APEL Test", "photographer_name": "Jeanne", "online_payment": False,
        "rgpd_days": 45, "price_pack": 15.5, "notification_email": "ops@example.com",
    }}, headers=admin_headers)
    assert r.status_code == 200, r.text
    s = (await client.get("/api/admin/settings", headers=admin_headers)).json()["settings"]
    assert s["shoot_date"] == "2027-03-15"
    assert s["revenue_share_pct"] == "12.5"
    assert s["online_payment"] == "false"
    assert s["rgpd_days"] == "45"
    assert s["price_pack"] == "15.5"
    # remise en état pour les autres tests
    await client.put("/api/admin/settings", json={"settings": {
        "online_payment": True, "rgpd_days": 60, "price_pack": 14}}, headers=admin_headers)


async def test_settings_validation_rejects_bad_values_atomically(client, admin_headers):
    before = (await client.get("/api/admin/settings", headers=admin_headers)).json()["settings"]
    for bad in (
        {"rgpd_days": 0}, {"rgpd_days": 9999}, {"shoot_date": "15/03/2027"}, {"revenue_share_pct": 150},
        {"price_digital": -1}, {"notification_email": "pas-un-email"}, {"inconnu": "x"}, {"online_payment": "peut-etre"},
    ):
        r = await client.put("/api/admin/settings", json={"settings": bad}, headers=admin_headers)
        assert r.status_code == 400, bad
    # un lot invalide ne modifie rien, même ses champs valides
    r = await client.put("/api/admin/settings", json={"settings": {"partner_name": "NE DOIT PAS PASSER", "rgpd_days": 0}},
                         headers=admin_headers)
    assert r.status_code == 400
    assert (await client.get("/api/admin/settings", headers=admin_headers)).json()["settings"] == before


async def test_director_cannot_edit_settings(client, director_headers):
    r = await client.put("/api/admin/settings", json={"settings": {"partner_name": "x"}}, headers=director_headers)
    assert r.status_code == 403


async def test_settings_are_isolated_between_schools(client, admin_headers, other_admin_headers):
    await client.put("/api/admin/settings", json={"settings": {"partner_name": "Partenaire A"}}, headers=admin_headers)
    a = (await client.get("/api/admin/settings", headers=admin_headers)).json()["settings"]["partner_name"]
    b = (await client.get("/api/admin/settings", headers=other_admin_headers)).json()["settings"]["partner_name"]
    assert a == "Partenaire A" and b != "Partenaire A"


async def test_settings_change_is_audited(client, admin_headers):
    await client.put("/api/admin/settings", json={"settings": {"photographer_name": "Audit Test"}}, headers=admin_headers)
    ev = (await client.get("/api/admin/audit?action=settings.update", headers=admin_headers)).json()["events"]
    assert ev and ev[0]["details"]["photographer_name"]["to"] == "Audit Test"


async def test_deactivated_school_blocks_portal_and_director(client, admin_token):
    h = {"Authorization": f"Bearer {admin_token}"}
    sid = (await client.post("/api/admin/schools", json={"name": "A Fermer", "director_password": "motdepasse-8"},
                             headers=h)).json()["school"]["id"]
    token = (await client.post("/api/admin/login", json={"password": "motdepasse-8", "school": sid})).json()["token"]
    from core.db import get_db
    from core.timeutil import utcnow_iso
    with get_db() as conn:
        conn.execute("INSERT INTO families (code, family_name, created_at, school_id, consent_at) VALUES ('CLO-5005','Ferme',?,?,?)",
                     (utcnow_iso(), sid, utcnow_iso()))
        conn.commit()
    assert (await client.get("/api/portal/photos?code=CLO-5005")).status_code == 200
    await client.patch(f"/api/admin/schools/{sid}", json={"active": False}, headers=h)
    assert (await client.get("/api/portal/photos?code=CLO-5005")).status_code == 404
    assert (await client.get("/api/director/dashboard", headers={"Authorization": f"Bearer {token}"})).status_code == 401
    assert (await client.post("/api/admin/login", json={"password": "motdepasse-8", "school": sid})).status_code == 401


async def test_schools_listing_has_counts(client, admin_token):
    r = await client.get("/api/admin/schools", headers={"Authorization": f"Bearer {admin_token}"})
    schools = {s["id"]: s for s in r.json()["schools"]}
    assert SCHOOL in schools and OTHER_SCHOOL in schools
    assert schools[SCHOOL]["families"] >= 2


async def test_families_are_isolated_between_schools(client, admin_headers, other_admin_headers):
    mine = {f["code"] for f in (await client.get("/api/admin/families", headers=admin_headers)).json()["families"]}
    theirs = {f["code"] for f in (await client.get("/api/admin/families", headers=other_admin_headers)).json()["families"]}
    assert "TST-1001" in mine and "OTH-2002" not in mine
    assert "OTH-2002" in theirs and "TST-1001" not in theirs


async def test_legacy_single_school_database_is_migrated(tmp_path, monkeypatch):
    """Une base d'avant le multi-école (table settings globale) devient une école."""
    import sqlite3
    from core import config
    legacy = tmp_path / "legacy.db"
    c = sqlite3.connect(legacy)
    c.executescript("""
        CREATE TABLE settings (key TEXT PRIMARY KEY, value TEXT);
        INSERT INTO settings VALUES ('school_name','École Historique'),('rgpd_days','30'),('partner_name','APEL Histo');
        CREATE TABLE families (code TEXT PRIMARY KEY, family_name TEXT NOT NULL, email TEXT, created_at TEXT);
        INSERT INTO families VALUES ('OLD-1111','Ancien',NULL,'2026-01-01');
        CREATE TABLE orders (id TEXT PRIMARY KEY, family_code TEXT NOT NULL, customer_name TEXT, customer_email TEXT,
            shipping_address TEXT, total REAL NOT NULL, status TEXT NOT NULL DEFAULT 'pending', items_json TEXT NOT NULL,
            created_at TEXT NOT NULL);
        INSERT INTO orders VALUES ('o1','OLD-1111','n','e',NULL,9,'pending','[]','2026-01-02');
    """)
    c.commit(); c.close()
    monkeypatch.setattr(config, "DB_PATH", legacy)
    import main
    from core.db import get_db
    from services import school_service
    main.init_all()
    schools = school_service.list_schools()
    assert len(schools) == 1 and schools[0]["name"] == "École Historique"
    sid = schools[0]["id"]
    assert school_service.get_settings(sid)["rgpd_days"] == "30"
    assert school_service.get_settings(sid)["partner_name"] == "APEL Histo"
    with get_db() as conn:
        assert conn.execute("SELECT school_id FROM families WHERE code='OLD-1111'").fetchone()["school_id"] == sid
        assert conn.execute("SELECT school_id FROM orders WHERE id='o1'").fetchone()["school_id"] == sid


def test_brand_color_is_validated_and_must_keep_white_text_readable():
    import pytest
    from services import school_service
    assert school_service._normalize("brand_color", "#1a2b4c") == "#1A2B4C"
    for bad in ("red", "#12", "#FFFF00", "#F7F4EE"):
        with pytest.raises(school_service.SettingsError):
            school_service._normalize("brand_color", bad)


def test_card_header_uses_the_school_colour():
    import io
    from PIL import Image
    from services import card_service
    kw = dict(code="MAR-AAA-BBB", family_name="Test", students=[], school_name="X",
              portal_url="https://p.example", rgpd_days="60")
    plain = Image.open(io.BytesIO(card_service.render_card(**kw))).convert("RGB")
    green = Image.open(io.BytesIO(card_service.render_card(**kw, brand_color="#0B6B3A"))).convert("RGB")
    assert green.getpixel((card_service.CARD_W - 20, 10)) == (11, 107, 58)
    assert plain.getpixel((card_service.CARD_W - 20, 10)) != (11, 107, 58)
