"""عميل سجل الموديولات (OTA) على الحافة — يسحب الحزم الموقّعة، يتحقق، ويحمّلها ساخنة.

يستطلع modules_version؛ عند تغيّره ينزّل الجديد/المحدّث، **يتحقق التوقيع** بالمفتاح العام
المُزوّد (VEEDON_MODULE_PUBKEY)، ثم يسجّل نسخة موديول لكل كاميرا مفعّلة له.
"""
import base64
import os

import requests

from . import loader


class ModuleOTA:
    def __init__(self, engine, cloud, headers, pubkey_b64, modules_dir,
                 assignments_fn, log=print):
        self.engine = engine
        self.cloud = cloud.rstrip("/")
        self.headers = headers
        self.pub = base64.b64decode(pubkey_b64) if pubkey_b64 else b""
        self.modules_dir = modules_dir
        self.assignments_fn = assignments_fn      # (key) -> [(camera, config), …]
        self.log = log
        self._mv = -1
        self._loaded = {}                         # key -> version مُحمَّل

    def sync(self):
        if not self.pub:
            return                                # لا مفتاح عام مُزوّد → لا تحميل (أمان)
        try:
            r = requests.get(f"{self.cloud}/api/device/modules",
                             headers=self.headers, timeout=20)
            if not r.ok:
                return
            data = r.json()
        except Exception as exc:
            self.log(f"[ota] list failed: {exc}")
            return
        if data.get("modules_version") == self._mv:
            return
        for key, info in (data.get("modules") or {}).items():
            ver = info.get("latest")
            if self._loaded.get(key) == ver:
                continue
            try:
                self._install_and_register(key, ver, info.get("triggers"))
                self._loaded[key] = ver
            except Exception as exc:              # حزمة مرفوضة/تالفة لا تُسقط الباقي
                self.log(f"[ota] module {key} v{ver} rejected: {exc}")
        self._mv = data.get("modules_version")

    def _install_and_register(self, key, ver, triggers):
        vmod = requests.get(f"{self.cloud}/api/device/modules/{key}/{ver}",
                            headers=self.headers, timeout=60).content
        man = loader.install(vmod, self.pub, self.modules_dir)   # يتحقق التوقيع
        cls = loader.load_detector_class(man["_entry"], key, ver)
        model = man.get("_model")
        for camera, config in self.assignments_fn(key):
            self.engine.unregister(key, camera)
            self.engine.register(key, cls(), camera, config, model, ver,
                                 triggers=man.get("triggers") or triggers)
        self.log(f"[ota] loaded {key} v{ver} على {len(self.assignments_fn(key))} كاميرا")
