/* Bonyan ERP — المساعد الصوتي الذكي (عربي)
   يسمع عبر Web Speech API ويفهم الأمر وينفّذه:
   «كشف أحمد» → كشف حسابه · «حديد ١٢» → رصيده بالمخزن · «النواقص» → قائمة الشراء
   «أرباح السنة» → التقارير · «فاتورة رقم ١٠٤٢٨» → فتحها · أسماء الشاشات → تنقّل.
   محلّل النوايا window.BnyVoiceParse(text, user) دالة نقية (قابلة للاختبار)،
   مع fallback كتابي عند غياب المايك، ورد صوتي مختصر (speechSynthesis). */

(function () {
  /* ---------- تطبيع عربي + مطابقة ضبابية ---------- */
  function bnyNorm(s) {
    return String(s || "")
      .replace(/[ً-ْٰـ]/g, "")      // تشكيل وتطويل
      .replace(/[أإآٱ]/g, "ا").replace(/ة/g, "ه").replace(/ى/g, "ي").replace(/ؤ/g, "و").replace(/ئ/g, "ي")
      .replace(/[٠-٩]/g, function (d) { return "٠١٢٣٤٥٦٧٨٩".indexOf(d); })
      .replace(/[^0-9a-z؀-ۿ\s]/gi, " ")
      .replace(/\s+/g, " ").trim().toLowerCase();
  }
  function bnyToks(s) {
    return bnyNorm(s).split(" ").map(function (t) { return t.replace(/^(ال|لل|وال|بال)/, ""); }).filter(function (t) { return t.length > 1; });
  }
  // نسبة كلمات الاستعلام المطابقة لاسم الكيان (تطابق أو بداية كلمة)
  function bnyScore(qToks, name) {
    var nToks = bnyToks(name);
    if (!nToks.length || !qToks.length) return 0;
    var hit = 0;
    qToks.forEach(function (q) {
      if (nToks.some(function (n) { return n === q || n.indexOf(q) === 0 || q.indexOf(n) === 0; })) hit++;
    });
    return hit / qToks.length;
  }
  // أفضل المطابقات في قائمة كيانات {الحد الأدنى 0.5 = نصف الكلمات}
  function bnyBest(qToks, list, nameOf) {
    var scored = list.map(function (e) { return { e: e, s: bnyScore(qToks, nameOf(e)) }; })
      .filter(function (x) { return x.s >= 0.5; })
      .sort(function (a, b) { return b.s - a.s; });
    if (!scored.length) return { match: null, choices: [] };
    var top = scored[0].s;
    var ties = scored.filter(function (x) { return x.s >= top - 0.01; });
    return ties.length === 1
      ? { match: ties[0].e, choices: [] }
      : { match: null, choices: ties.slice(0, 4).map(function (x) { return x.e; }) };
  }
  var fmtN = function (n) { return Number(n || 0).toLocaleString("en-US"); };

  /* ---------- بناة النتائج ---------- */
  function resCustomer(c) {
    var ans = "المستحق عليه: " + fmtN(c.balance) + " د.ع" + (c.balanceUsd ? " + " + fmtN(c.balanceUsd) + " $" : "");
    return { kind: "statement", icon: "users", title: "كشف حساب العميل: " + c.name, answer: ans,
      speak: "المستحق على " + c.name + " " + fmtN(c.balance) + " دينار",
      run: { screen: "customers", custId: c.id } };
  }
  function resSupplier(s) {
    var ans = "المستحق له: " + fmtN(s.payable) + " د.ع" + (s.payableUsd ? " + " + fmtN(s.payableUsd) + " $" : "");
    return { kind: "statement", icon: "supplier", title: "كشف حساب المورد: " + s.name, answer: ans,
      speak: "المستحق للمورد " + s.name + " " + fmtN(s.payable) + " دينار",
      run: { screen: "suppliers", supId: s.id } };
  }
  function resMaterial(m) {
    var packs = window.BnyStock && window.BnyStock(m);
    var ans = m.stock > 0
      ? "متوفر: " + fmtN(m.stock) + " " + m.unit + (packs ? " (" + packs + ")" : "") + " · مخزن " + (m.wh || "—")
      : "نفدت من المخزن!";
    return { kind: "stock", icon: "inventory", title: "المادة: " + m.name, answer: ans,
      speak: m.stock > 0 ? "متوفر " + fmtN(m.stock) + " " + m.unit + " من " + m.name : m.name + " نفدت من المخزن",
      run: { screen: "inventory", search: m.name } };
  }

  /* ---------- محلّل النوايا (نقي وقابل للاختبار) ---------- */
  window.BnyVoiceParse = function (text, user) {
    var D = window.BnyData || {};
    var can = function (perm) { return !user || window.BnyCan(user, perm); };
    var denied = function (what) { return { kind: "denied", icon: "alert", title: "غير مسموح", answer: "لا تملك صلاحية " + what + "." }; };
    var t = bnyNorm(text);
    if (!t) return { kind: "none" };

    // ١) فاتورة برقم → فتح مباشر
    var mInv = t.match(/فاتور\S*\s*(?:رقم\s*)?(\d+)/);
    if (mInv) {
      if (!can("invoices_view")) return denied("عرض الفواتير");
      var inv = (D.invoices || []).find(function (i) { return String(i.num) === mInv[1] || i.no === mInv[1]; });
      return inv
        ? { kind: "invoice", icon: "invoice", title: "فتح الفاتورة #" + inv.no, answer: inv.party + " · " + fmtN(inv.total) + " " + (inv.cur === "usd" ? "$" : "د.ع"), run: { invoiceNo: inv.no }, speak: "فتح الفاتورة " + mInv[1] }
        : { kind: "none", icon: "invoice", title: "لا توجد فاتورة بالرقم " + mInv[1] };
    }

    // ٢) فاتورة جديدة / بيع
    if (/فاتوره جديد|بيع جديد|افتح فاتوره|انشئ فاتوره|سو فاتوره/.test(t)) {
      return can("pos") ? { kind: "nav", icon: "invoice", title: "فاتورة بيع جديدة", run: { screen: "pos" }, speak: "فاتورة جديدة" } : denied("إنشاء الفواتير");
    }

    // ٣) النواقص / المطلوب شراؤها
    if (/نواقص|ناقص|مطلوب شرا|يجب شرا|اعاده طلب|احتاج شرا|نحتاج شرا|خلصان|توفير مواد/.test(t)) {
      if (!can("inventory_view")) return denied("عرض المخزن");
      var low = window.BnyLowStockMaterials ? window.BnyLowStockMaterials() : [];
      return { kind: "reorder", icon: "alert", title: "المواد المطلوب شراؤها",
        answer: low.length ? low.length + " مادة تحتاج شراء — أبرزها: " + low.slice(0, 3).map(function (m) { return m.name; }).join("، ") : "لا نواقص — كل المواد ضمن الحد ✓",
        speak: low.length ? "لديك " + low.length + " مادة تحتاج شراء" : "لا توجد نواقص",
        run: { screen: "inventory", filter: "reorder" } };
    }

    // ٤) المواد الراكدة
    if (/راكد/.test(t)) {
      if (!can("inventory_view")) return denied("عرض المخزن");
      var stg = window.BnyStagnantMaterials ? window.BnyStagnantMaterials() : [];
      return { kind: "stagnant", icon: "inventory", title: "المواد الراكدة",
        answer: stg.length ? stg.length + " مادة راكدة (دون بيع)" : "لا مواد راكدة ✓",
        speak: stg.length ? stg.length + " مادة راكدة" : "لا مواد راكدة",
        run: { screen: "inventory" } };
    }

    // ٥) الأرباح / التقارير / المبيعات
    if (/ربح|ارباح|تقرير|تقارير|مبيعات/.test(t)) {
      if (!can("reports")) return denied("التقارير");
      var year = new Date().getFullYear() + "";
      var sales = (D.invoices || []).filter(function (i) { return i.type === "sale" && i.cur === "iqd" && (i.date || "").indexOf(year) === 0; });
      var totalSales = sales.reduce(function (s, i) { return s + (Number(i.total) || 0); }, 0);
      var costOf = {}; (D.materials || []).forEach(function (m) { costOf[m.sku] = Number(m.cost) || 0; });
      var profit = sales.reduce(function (s, i) {
        return s + (i.items || []).reduce(function (x, it) {
          var c = it.sku != null && costOf[it.sku] != null ? costOf[it.sku] : 0;
          return x + ((Number(it.price) || 0) - c) * (Number(it.qty) || 0);
        }, 0);
      }, 0);
      return { kind: "reports", icon: "chart", title: "أرباح ومبيعات السنة",
        answer: "مبيعات " + year + ": " + fmtN(totalSales) + " د.ع · أرباح تقديرية: " + fmtN(Math.round(profit)) + " د.ع",
        speak: "مبيعات السنة " + fmtN(totalSales) + " دينار",
        run: { screen: "reports" } };
    }

    // ٦) ديون العملاء
    if (/ديون|مديونيه|اعلي الديون/.test(t)) {
      if (!can("customers")) return denied("العملاء");
      var totalDebt = (D.customers || []).reduce(function (s, c) { return s + (window.BnyToIqd ? window.BnyToIqd(c.balance, c.balanceUsd) : (c.balance || 0)); }, 0);
      return { kind: "debts", icon: "wallet", title: "ديون العملاء",
        answer: "إجمالي الديون: " + fmtN(Math.round(totalDebt)) + " د.ع (بالمكافئ)",
        speak: "إجمالي ديون العملاء " + fmtN(Math.round(totalDebt)) + " دينار",
        run: { screen: "customers" } };
    }

    // ٧) تنقّل مباشر بأسماء الشاشات
    var NAVS = [
      [/^(الرئيسيه|رئيسيه|لوحه التحكم|الصفحه الرئيسيه|هوم)$/, "dashboard", "dashboard", "الرئيسية"],
      [/^(الفواتير|فواتير)$/, "invoices_view", "invoices", "الفواتير"],
      [/^(العملاء|عملاء)$/, "customers", "customers", "العملاء"],
      [/^(الموردون|الموردين|موردين)$/, "suppliers", "suppliers", "الموردون"],
      [/^(المواد|مواد|المخزن|مخزن)$/, "inventory_view", "inventory", "المواد"],
      [/^(المخازن|اداره المخازن)$/, "inventory_edit", "warehouses", "إدارة المخازن"],
      [/^(التسعير|تسعير|الاسعار)$/, "pricing", "pricing", "التسعير"],
      [/^(الحركات|السجل|سجل الحركات)$/, "activity", "activity", "الحركات"],
      [/^(الاعدادات|اعدادات الفاتوره)$/, "invoice_settings", "settings", "إعدادات الفاتورة"],
      [/^(المستخدمون|المستخدمين|الصلاحيات)$/, "users_manage", "users", "صلاحيات المستخدمين"],
    ];
    for (var i = 0; i < NAVS.length; i++) {
      if (NAVS[i][0].test(t)) {
        return can(NAVS[i][1])
          ? { kind: "nav", icon: "dashboard", title: "الانتقال إلى: " + NAVS[i][3], run: { screen: NAVS[i][2] }, speak: NAVS[i][3] }
          : denied(NAVS[i][3]);
      }
    }

    // ٨) كشف/حساب + اسم → عميل أو مورد (وإلا مادة)
    var isStatement = /كشف|حساب|رصيد|دين/.test(t);
    // فلترة كلمات الأوامر على مستوى الكلمة (\b لا يعمل مع العربية)
    var STOP = { "كشف": 1, "حساب": 1, "رصيد": 1, "دين": 1, "ديون": 1, "مخزون": 1, "متوفر": 1, "كم": 1, "عندنا": 1, "عدنا": 1, "اريد": 1, "افتح": 1, "اعرض": 1, "ورجيني": 1, "شوف": 1, "سعر": 1, "شنو": 1, "وين": 1, "هل": 1, "ماذا": 1, "عند": 1, "في": 1, "من": 1, "عن": 1 };
    var qToks = bnyToks(t).filter(function (tok) { return !STOP[tok]; });
    if (qToks.length) {
      if (isStatement) {
        if (can("customers")) {
          var bc = bnyBest(qToks, (D.customers || []).filter(function (c) { return !c.walkin; }), function (c) { return c.name; });
          if (bc.match) return resCustomer(bc.match);
          if (bc.choices.length) return { kind: "choices", icon: "users", title: "أي عميل تقصد؟", choices: bc.choices.map(function (c) { return { label: c.name, result: resCustomer(c) }; }) };
        }
        if (can("suppliers")) {
          var bs = bnyBest(qToks, D.suppliers || [], function (s) { return s.name; });
          if (bs.match) return resSupplier(bs.match);
          if (bs.choices.length) return { kind: "choices", icon: "supplier", title: "أي مورد تقصد؟", choices: bs.choices.map(function (s) { return { label: s.name, result: resSupplier(s) }; }) };
        }
      }
      // مادة (بكلمة مفتاحية مخزنية أو باسم مجرد)
      if (can("inventory_view")) {
        var bm = bnyBest(qToks, D.materials || [], function (m) { return m.name; });
        if (bm.match) return resMaterial(bm.match);
        if (bm.choices.length) return { kind: "choices", icon: "inventory", title: "أي مادة تقصد؟", choices: bm.choices.map(function (m) { return { label: m.name, result: resMaterial(m) }; }) };
      }
      // كشف بلا كلمة مفتاحية؟ جرّب الأشخاص أخيرًا
      if (!isStatement) {
        if (can("customers")) {
          var bc2 = bnyBest(qToks, (D.customers || []).filter(function (c) { return !c.walkin; }), function (c) { return c.name; });
          if (bc2.match) return resCustomer(bc2.match);
        }
        if (can("suppliers")) {
          var bs2 = bnyBest(qToks, D.suppliers || [], function (s) { return s.name; });
          if (bs2.match) return resSupplier(bs2.match);
        }
      }
    }
    return { kind: "none" };
  };

  /* ---------- تنفيذ نتيجة ---------- */
  function bnyRunResult(res, onAction) {
    var run = res.run || {};
    if (run.invoiceNo) { window.BnyOpenInvoice(run.invoiceNo); return; }
    if (run.custId != null) window.BnyPendingCustomerId = run.custId;
    if (run.supId != null) window.BnyPendingSupplierId = run.supId;
    if (run.search) window.BnyPendingInvSearch = run.search;
    if (run.filter) window.BnyPendingInvFilter = run.filter;
    if (run.screen) onAction(run.screen);
  }
  function bnySpeak(text) {
    try {
      if (!text || !window.speechSynthesis) return;
      window.speechSynthesis.cancel();
      var u = new SpeechSynthesisUtterance(text);
      u.lang = "ar"; u.rate = 1.05;
      window.speechSynthesis.speak(u);
    } catch (e) {}
  }

  var HINTS = [
    "«كشف أحمد المقاول» — كشف حساب عميل أو مورد",
    "«حديد ١٢» أو «كم عندنا إسمنت» — رصيد مادة بالمخزن",
    "«شنو النواقص» — المواد المطلوب شراؤها",
    "«أرباح السنة» — التقارير ومخطط الأرباح",
    "«فاتورة رقم ١٠٤٢٨» — فتح فاتورة مباشرة",
    "«فاتورة جديدة» · «العملاء» · «الحركات» — تنقّل سريع",
  ];

  /* ---------- الواجهة ---------- */
  function VoiceOverlay({ open, onClose, onAction, user }) {
    const I = window.BnyIcon;
    const { Button, Input } = window.BonyanDesignSystem_ad3ca0;
    const [phase, setPhase] = React.useState("listen"); // listen | typing | result
    const [transcript, setTranscript] = React.useState("");
    const [res, setRes] = React.useState(null);
    const [typed, setTyped] = React.useState("");
    const recRef = React.useRef(null);
    const timerRef = React.useRef(null);
    const SR = window.SpeechRecognition || window.webkitSpeechRecognition;

    const finish = (text) => {
      const r = window.BnyVoiceParse(text, user);
      r._heard = text;
      setRes(r); setPhase("result");
      if (r.speak) bnySpeak(r.speak);
      // تنفيذ تلقائي بعد مهلة قصيرة (يمكن إلغاؤه) — إلا للاختيارات/الرفض/عدم الفهم
      if (r.run && r.kind !== "choices") {
        timerRef.current = setTimeout(() => { bnyRunResult(r, onAction); onClose(); }, 1400);
      }
    };
    const cancelTimer = () => { if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } };

    const startMic = React.useCallback(() => {
      setTranscript(""); setRes(null); setPhase("listen");
      if (!SR) { setPhase("typing"); return; }
      try {
        const rec = new SR();
        recRef.current = rec;
        rec.lang = "ar-IQ"; rec.interimResults = true; rec.continuous = false; rec.maxAlternatives = 1;
        let finalText = "";
        rec.onresult = (ev) => {
          let interim = "";
          for (let i = ev.resultIndex; i < ev.results.length; i++) {
            if (ev.results[i].isFinal) finalText += ev.results[i][0].transcript;
            else interim += ev.results[i][0].transcript;
          }
          setTranscript(finalText || interim);
          if (finalText) { try { rec.stop(); } catch (e) {} finish(finalText); }
        };
        rec.onerror = () => setPhase("typing");
        rec.onend = () => { if (!finalText) setPhase((p) => (p === "listen" ? "typing" : p)); };
        rec.start();
      } catch (e) { setPhase("typing"); }
    }, [SR, user]);

    React.useEffect(() => {
      if (!open) {
        cancelTimer();
        try { if (recRef.current) recRef.current.abort(); } catch (e) {}
        setPhase("listen"); setTranscript(""); setRes(null); setTyped("");
        return;
      }
      startMic();
      return () => { cancelTimer(); try { if (recRef.current) recRef.current.abort(); } catch (e) {} };
    }, [open]); // eslint-disable-line

    if (!open) return null;
    const Icon = res && res.icon && I[res.icon] ? I[res.icon] : I.mic;

    return (
      <div onClick={() => { cancelTimer(); onClose(); }} style={{ position: "fixed", inset: 0, background: "var(--surface-overlay)", backdropFilter: "blur(3px)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1200, padding: 16 }}>
        <div onClick={(e) => e.stopPropagation()} style={{ width: "100%", maxWidth: 480, background: "var(--surface-card)", borderRadius: "var(--radius-xl)", boxShadow: "var(--shadow-xl)", padding: 26, textAlign: "center" }}>

          {/* أيقونة الحالة */}
          <div style={{ position: "relative", width: 84, height: 84, margin: "0 auto 16px" }}>
            {phase === "listen" && <span style={{ position: "absolute", inset: 0, borderRadius: "50%", background: "var(--red-100)", animation: "bnyPulse 1.4s ease-out infinite" }} />}
            <span style={{ position: "relative", display: "inline-flex", alignItems: "center", justifyContent: "center", width: 84, height: 84, borderRadius: "50%",
              background: phase === "listen" ? "var(--danger)" : (res && res.run ? "var(--success)" : "var(--brand)"), color: "#fff" }}>
              {phase === "result" ? <Icon size={36} /> : <I.mic size={36} />}
            </span>
          </div>

          {/* استماع */}
          {phase === "listen" && (
            <>
              <div style={{ fontSize: 17, fontWeight: 700, color: "var(--text-strong)" }}>جارٍ الاستماع…</div>
              <div style={{ color: "var(--text-muted)", fontSize: 13, marginTop: 4 }}>تكلّم الآن — مثل: «كشف أحمد» أو «شنو النواقص»</div>
              <div style={{ marginTop: 14, minHeight: 44, padding: "11px 14px", background: "var(--surface-sunken)", borderRadius: "var(--radius-md)", color: "var(--text-body)", fontSize: 15 }}>
                {transcript || "…"}
              </div>
              <div style={{ marginTop: 14 }}>
                <Button variant="secondary" size="sm" onClick={() => { try { if (recRef.current) recRef.current.abort(); } catch (e) {} setPhase("typing"); }}>اكتب الأمر بدلًا من ذلك</Button>
              </div>
            </>
          )}

          {/* كتابة */}
          {phase === "typing" && (
            <>
              <div style={{ fontSize: 17, fontWeight: 700, color: "var(--text-strong)" }}>اكتب أمرك</div>
              {!SR && <div style={{ color: "var(--text-muted)", fontSize: 12, marginTop: 4 }}>المتصفح لا يدعم الإدخال الصوتي — الكتابة تعمل بنفس الذكاء.</div>}
              <form onSubmit={(e) => { e.preventDefault(); if (typed.trim()) finish(typed); }} style={{ marginTop: 14 }}>
                <Input value={typed} onChange={(e) => setTyped(e.target.value)} placeholder="مثال: كشف أحمد المقاول" autoFocus />
                <div style={{ display: "flex", gap: 10, marginTop: 12 }}>
                  {SR && <Button variant="secondary" block icon={<I.mic size={16} />} onClick={startMic} type="button">استماع</Button>}
                  <Button variant="accent" block type="submit" icon={<I.check size={16} />}>تنفيذ</Button>
                </div>
              </form>
            </>
          )}

          {/* النتيجة */}
          {phase === "result" && res && (
            <>
              {res._heard && <div style={{ fontSize: 12, color: "var(--text-faint)", marginBottom: 6 }}>سمعت: «{res._heard}»</div>}
              {res.kind === "none" ? (
                <>
                  <div style={{ fontSize: 17, fontWeight: 700, color: "var(--text-strong)" }}>لم أفهم الأمر</div>
                  <div style={{ textAlign: "start", marginTop: 12, padding: "12px 14px", background: "var(--surface-sunken)", borderRadius: "var(--radius-md)" }}>
                    <div style={{ fontSize: 12, fontWeight: 700, color: "var(--text-muted)", marginBottom: 8 }}>أمثلة مما يمكنك قوله:</div>
                    {HINTS.map((h, i) => <div key={i} style={{ fontSize: 12.5, color: "var(--text-body)", padding: "3px 0" }}>{h}</div>)}
                  </div>
                </>
              ) : res.kind === "choices" ? (
                <>
                  <div style={{ fontSize: 17, fontWeight: 700, color: "var(--text-strong)" }}>{res.title}</div>
                  <div style={{ display: "flex", flexDirection: "column", gap: 8, marginTop: 14 }}>
                    {res.choices.map((c, i) => (
                      <Button key={i} variant="secondary" block onClick={() => { bnySpeak(c.result.speak); bnyRunResult(c.result, onAction); onClose(); }}>{c.label}</Button>
                    ))}
                  </div>
                </>
              ) : (
                <>
                  <div style={{ fontSize: 17, fontWeight: 700, color: "var(--text-strong)" }}>{res.title}</div>
                  {res.answer && (
                    <div style={{ display: "inline-block", marginTop: 12, padding: "10px 16px", background: res.kind === "denied" ? "var(--danger-soft)" : "var(--brand-soft)", color: res.kind === "denied" ? "var(--danger-text)" : "var(--brand-strong)", borderRadius: "var(--radius-md)", fontWeight: 600, fontSize: 14, lineHeight: 1.7 }}>
                      {res.answer}
                    </div>
                  )}
                  {res.run && <div style={{ fontSize: 11.5, color: "var(--text-faint)", marginTop: 10 }}>سيُنفَّذ تلقائيًا…</div>}
                </>
              )}
              <div style={{ display: "flex", gap: 10, marginTop: 18 }}>
                <Button variant="secondary" block icon={<I.mic size={16} />} onClick={() => { cancelTimer(); startMic(); }}>أمر آخر</Button>
                {res.run && res.kind !== "choices"
                  ? <Button variant="accent" block icon={<I.check size={16} />} onClick={() => { cancelTimer(); bnyRunResult(res, onAction); onClose(); }}>تنفيذ الآن</Button>
                  : <Button variant="accent" block onClick={() => { cancelTimer(); onClose(); }}>إغلاق</Button>}
              </div>
            </>
          )}
        </div>
      </div>
    );
  }
  window.VoiceOverlay = VoiceOverlay;
})();
