/**
 * Fichier  : assets/js/ScannerService.js
 * Auteur   : KREMER Régis
 * Version  : 2.2.0
 * Date     : 2026-02-21
 * Description : JS — Service scanner codes-barres (Quagga2 + Html5Qrcode)
 *
 * Changelog :
 *   v2.1.0 (2026-02-21) — Version initiale auditée et sécurisée
 *   v2.1.1 (2026-02-21) — Corrections sécurité, utils.js centralisé
 *   v2.2.0 (2026-02-21) — Permissions magasins, bons de commande, rapport d'écart,
 *                      import CSV, historique prix, bon de livraison multi-lignes
 */
// ================================================================
// ScannerService.js — Unified camera + image decoding (html5-qrcode)
// Modes: 'barcode' | 'qrcode' | 'auto'
// ================================================================
(function () {
  "use strict";

  function hasHtml5() {
    return typeof window.Html5Qrcode !== "undefined";
  }

  function supportedFormats() {
    // Html5QrcodeSupportedFormats exists in recent versions
    return (typeof window.Html5QrcodeSupportedFormats !== "undefined")
      ? window.Html5QrcodeSupportedFormats
      : null;
  }

  function getFormatsForMode(mode) {
    const fm = supportedFormats();
    if (!fm) return undefined; // let lib decide
    const all = Object.values(fm);

    const qr = fm.QR_CODE ?? fm.QRCode ?? null;
    // Common barcodes
    const barcodeCandidates = [
      fm.CODE_128, fm.CODE_39, fm.CODE_93, fm.CODABAR,
      fm.EAN_13, fm.EAN_8, fm.ITF, fm.UPC_A, fm.UPC_E
    ].filter(Boolean);

    if (mode === "qrcode") return qr ? [qr] : all;
    if (mode === "barcode") return barcodeCandidates.length ? barcodeCandidates : all.filter(f => f !== qr);
    return all; // auto
  }

  function buildQrbox(mode) {
    // html5-qrcode accepts number or function(viewfinderWidth, viewfinderHeight)
    if (mode === "qrcode") {
      return (vw, vh) => {
        const size = Math.floor(Math.min(vw, vh) * 0.68);
        return { width: size, height: size };
      };
    }
    // barcode / auto: wide rectangle centered (better for EAN/Code128)
    return (vw, vh) => {
      const width = Math.floor(vw * 0.82);
      const height = Math.floor(vh * 0.34);
      return { width, height };
    };
  }

  const ScannerService = {
    _html5: null,
    _running: false,
    _targetId: null,
    _cooldownUntil: 0,
    _lastText: "",
    _lastTs: 0,

    
async start(opts) {
      const {
        target,
        mode = "auto",
        onDetected,
        onError,
        fps = 12
      } = opts || {};

      const targetId = this._ensureTargetId(target);
      const el = document.getElementById(targetId);
      if (el) {
        const r = el.getBoundingClientRect();
        if (r.height < 120) {
          // Ensure visible surface for mobile browsers (otherwise camera may start but not render)
          el.style.minHeight = el.style.minHeight || "280px";
          if (!el.style.height) el.style.height = "280px";
        }
      }

      // Always stop any previous instance
      await this.stop();

      // Prefer Html5Qrcode for both QR and barcode (broad support). Quagga remains for image decode.
      if (typeof Html5Qrcode === "undefined") {
        const e = new Error("Html5Qrcode is not loaded");
        if (typeof onError === "function") onError(e);
        throw e;
      }

      try {
        // Prepare instance
        this._html5 = new Html5Qrcode(targetId);
        this._running = true;

        // Config: avoid qrbox/aspectRatio for barcode/auto to prevent viewport cropping/offsets.
        const config = { fps: Number(fps) || 12 };
        if (mode === "qr") {
          config.qrbox = 250;
        }

        // Formats: in auto, support common barcodes + QR.
        if (typeof Html5QrcodeSupportedFormats !== "undefined") {
          if (mode === "qr") {
            config.formatsToSupport = [Html5QrcodeSupportedFormats.QR_CODE];
          } else {
            config.formatsToSupport = [
              Html5QrcodeSupportedFormats.QR_CODE,
              Html5QrcodeSupportedFormats.EAN_13,
              Html5QrcodeSupportedFormats.EAN_8,
              Html5QrcodeSupportedFormats.UPC_A,
              Html5QrcodeSupportedFormats.UPC_E,
              Html5QrcodeSupportedFormats.CODE_128,
              Html5QrcodeSupportedFormats.CODE_39,
              Html5QrcodeSupportedFormats.ITF,
              Html5QrcodeSupportedFormats.CODABAR
            ];
          }
        }

        const onSuccess = (decodedText) => {
          if (!this._running) return;
          const code = String(decodedText || "").trim();
          if (!code) return;
          if (typeof onDetected === "function") onDetected(code);
        };

        const onFail = () => { /* silent */ };

        // Attempt 1: facingMode (most mobile-friendly)
        try {
          await this._html5.start({ facingMode: "environment" }, config, onSuccess, onFail);
          return;
        } catch (e1) {
          // Attempt 2: fallback to first available camera deviceId
          try {
            const cams = await Html5Qrcode.getCameras();
            if (cams && cams.length) {
              await this._html5.start(cams[0].id, config, onSuccess, onFail);
              return;
            }
          } catch (_) { /* ignore */ }
          throw e1;
        }
      } catch (e) {
        this._running = false;
        try { this._html5 && this._html5.clear(); } catch (_) {}
        this._html5 = null;

        if (typeof onError === "function") onError(e);
        else console.error(e);
        throw e;
      }
    },
async stop() {
      if (!this._html5) return;
      try {
        if (this._running) await this._html5.stop();
      } catch (_) {
        // ignore stop errors
      }
      try { this._html5.clear(); } catch (_) {}
      this._html5 = null;
      this._running = false;
      this._targetId = null;
      this._cooldownUntil = 0;
      this._lastText = "";
      this._lastTs = 0;
    },

    async scanImageFile(file) {
      if (!hasHtml5()) throw new Error("html5-qrcode non chargé.");
      if (!file) throw new Error("Aucun fichier image.");

      // Use a temp instance; html5-qrcode requires an element id even for scanFile
      const tmpId = "tmp-scan-file";
      if (!document.getElementById(tmpId)) {
        const tmp = document.createElement("div");
        tmp.id = tmpId;
        tmp.style.display = "none";
        document.body.appendChild(tmp);
      }

      const tmp = new Html5Qrcode(tmpId);
      try {
        const res = await tmp.scanFile(file, true);
        return (res || "").trim();
      } finally {
        try { tmp.clear(); } catch (_) {}
      }
    }
  };

  window.ScannerService = ScannerService;
  console.log("ScannerService loaded");
})();
