"""اختبار دخان لبوابة الأجهزة على مخطط لوحة Beyond Senses:
إعدادات الجهاز، تفعيل ميزة لكاميرا، إيقاف سداد (kill switch)، حدث بصورة،
تحليل VLM، وتنبيه واتساب."""

import io
import os
import tempfile

os.environ["VEEDON_DATA_DIR"] = tempfile.mkdtemp(prefix="veedon-test-")
os.environ.pop("ANTHROPIC_API_KEY", None)  # VLM بوضع "غير مفعّل"

from fastapi.testclient import TestClient  # noqa: E402

from app.db import SessionLocal  # noqa: E402
from app.main import app  # noqa: E402
from app.models import (Branch, Camera, CameraEventAssignment, Event,  # noqa: E402
                        EventType, Organization)


def test_device_gateway(monkeypatch):
    sent = []
    from app import notifier
    monkeypatch.setattr(notifier, "send_alert",
                        lambda numbers, text, path=None: sent.append((numbers, text)) or 1)

    with TestClient(app) as client:
        # بيانات كما تنشئها اللوحة (organizations/branches/cameras/assignments)
        db = SessionLocal()
        org = Organization(name="سلسلة الاختبار")
        db.add(org)
        db.flush()
        branch = Branch(organization_id=org.id, name="فرع الملقا",
                        alert_numbers="966500000000")
        db.add(branch)
        db.flush()
        cam = Camera(branch_id=branch.id, name="Kitchen 1",
                     rtsp_url="rtsp://x/1", frigate_identifier="kitchen_1")
        db.add(cam)
        db.flush()
        crowding = db.query(EventType).filter_by(feature_key="crowding").one()
        vlm_et = db.query(EventType).filter_by(feature_key="table_cleanliness").one()
        smoking = db.query(EventType).filter_by(feature_key="smoking").one()  # غير متاح بعد
        db.add_all([
            CameraEventAssignment(camera_id=cam.id, event_type_id=crowding.id,
                                  config={"threshold": 4}),
            CameraEventAssignment(camera_id=cam.id, event_type_id=vlm_et.id),
            CameraEventAssignment(camera_id=cam.id, event_type_id=smoking.id),
        ])
        db.commit()
        token, org_id, branch_id = branch.device_token, org.id, branch.id
        db.close()
        FP = "a" * 64
        auth = {"Authorization": f"Bearer {token}", "X-Device-Fingerprint": FP}

        # ── حماية الجهاز: بصمة + موافقة الأدمن ──
        assert client.get("/api/device/config").status_code == 401  # بلا token
        # قبل التسجيل: pending، والمحرك لا يحصل على الإعدادات
        assert client.get("/api/device/config", headers=auth).json()["status"] == "pending"
        # تسجيل بصمة الجهاز (جهاز فعلي، ليس VM) → pending بانتظار الأدمن
        act = client.post("/api/device/activate", headers=auth,
                          json={"fingerprint": FP,
                                "hardware_info": {"model": "Beelink N100"},
                                "is_vm": False}).json()
        assert act["authorized"] is False and act["status"] == "pending"
        # محاولة نسخة على جهاز آخر (بصمة مختلفة، نفس الـ token) → mismatch، لا تستبدل البصمة
        other = {"Authorization": f"Bearer {token}", "X-Device-Fingerprint": "b" * 64}
        assert client.get("/api/device/config", headers=other).json()["status"] \
            == "fingerprint_mismatch"
        # الأدمن يعتمد الجهاز
        db = SessionLocal()
        db.get(Branch, branch_id).device_status = "approved"
        db.commit()
        db.close()
        # جهاز افتراضي يُرفض حتى بعد الاعتماد (ما لم يسمح الأدمن)
        client.post("/api/device/activate", headers=auth,
                    json={"fingerprint": FP, "is_vm": True})
        assert client.get("/api/device/config", headers=auth).json()["status"] == "vm_blocked"
        client.post("/api/device/activate", headers=auth,
                    json={"fingerprint": FP, "is_vm": False})

        # إعدادات الجهاز: الكاميرا + الميزتان المتاحتان (smoking "قريباً" لا تظهر)
        cfg = client.get("/api/device/config", headers=auth).json()
        assert cfg["status"] == "active"
        assert cfg["cameras"] == [{"name": "kitchen_1", "rtsp_url": "rtsp://x/1"}]
        keys = {f["key"] for f in cfg["features"]}
        assert keys == {"crowding", "table_cleanliness"}
        crowd_cfg = next(f for f in cfg["features"] if f["key"] == "crowding")["config"]
        assert crowd_cfg["threshold"] == 4 and crowd_cfg["camera"] == "kitchen_1"
        assert crowd_cfg["cooldown_s"] == 600  # من default_config

        assert client.post("/api/device/heartbeat", headers=auth,
                           json={"agent_version": "0.1.0"}).json()["action"] == "run"

        # kill switch: إيقاف العميل (organizations.active=false كما تفعل اللوحة)
        db = SessionLocal()
        db.get(Organization, org_id).active = False
        db.commit()
        db.close()
        assert client.get("/api/device/config", headers=auth).json()["status"] == "suspended"
        r = client.post("/api/device/events", headers=auth,
                        data={"feature_key": "crowding", "camera": "kitchen_1"})
        assert r.status_code == 403
        db = SessionLocal()
        db.get(Organization, org_id).active = True
        db.commit()
        db.close()

        # حدث قاعدة فورية بصورة → صف في events + واتساب بالنص الصحيح
        r = client.post("/api/device/events", headers=auth,
                        data={"feature_key": "crowding", "camera": "kitchen_1",
                              "score": "7"},
                        files={"snapshot": ("s.jpg", io.BytesIO(b"fakejpg"),
                                            "image/jpeg")})
        eid = r.json()["id"]
        assert client.get(f"/snapshots/{eid}.jpg").status_code == 200
        db = SessionLocal()
        ev = db.query(Event).filter_by(event_type="crowding").one()
        assert ev.severity == "high" and ev.camera_id is not None
        assert ev.snapshot_url.endswith(f"{eid}.jpg")
        db.close()
        assert sent and sent[-1][0] == "966500000000"
        assert "فرع الملقا" in sent[-1][1] and "تكدس" in sent[-1][1]

        # حدث VLM → التحليل (بوضع غير مفعّل) يكتب ملاحظة في metadata
        client.post("/api/device/events", headers=auth,
                    data={"feature_key": "table_cleanliness", "camera": "kitchen_1",
                          "flagged": "false"},
                    files={"snapshot": ("s.jpg", io.BytesIO(b"fakejpg"),
                                        "image/jpeg")})
        db = SessionLocal()
        ev = db.query(Event).filter_by(event_type="table_cleanliness").one()
        assert "ai_note" in (ev.meta or {})
        db.close()
