/* =====================================================
   File: /home/jewellersbd/public_html/erp.jewellersbd.com/ui/js/newpur.js
   Module: নতুন ক্রয়
   Includes:
   - একক এন্ট্রি
   - মাল্টি এন্ট্রি: ভরি | আনা | রতি | পয়েন্ট
   - সাপ্লায়ার নাম/মোবাইল সার্চ
   - ক্রয় তালিকা display
   - ক্রয় তালিকা থেকে manual barcode create
   - barcode-এ কোনো ক্রয়/বিক্রয় মূল্য নেই
   ===================================================== */

(function () {
  'use strict';

  var VORI = 11.664;
  var ANA = VORI / 16;
  var ROTI = VORI / 96;
  var POINT = VORI / 960;
  var today = new Date().toISOString().slice(0, 10);

  var API = {
    parties: [
      '../api/parties/get_parties.php?limit=500',
      '../api/customers/get_parties.php?limit=500',
      '../api/customers/get_customers.php?limit=500',
      '../api/pawn/get_parties.php?limit=500'
    ],
    accounts: [
      '../api/cash/get_accounts.php',
      '../api/cash/accounts.php',
      '../api/cash/list_accounts.php'
    ],
    purchases: [
      '../api/purchases/get_purchases.php',
      '../api/purchases/list_purchases.php'
    ],
    addPurchase: '../api/purchases/add_purchase.php',
    createBarcodes: '../api/purchases/create_barcodes.php'
  };

  var KARAT_RATIO = {
    '24K': 100,
    '22K': 91.667,
    '21K': 87.5,
    '18K': 75,
    'other': 91.667
  };

  var parties = [];
  var accounts = [];
  var purchases = [];
  var multiRowCount = 0;
  var barcodeRowCount = 0;
  var currentBarcodePurchase = null;

  function el(id) {
    return document.getElementById(id);
  }

  function qsa(selector, parent) {
    return Array.prototype.slice.call((parent || document).querySelectorAll(selector));
  }

  function toNum(v) {
    return parseFloat(v || 0) || 0;
  }

  function toInt(v) {
    return parseInt(v || 0, 10) || 0;
  }

  function money(v) {
    return '৳' + Number(parseFloat(v || 0).toFixed(0)).toLocaleString('en-IN');
  }

  function esc(v) {
    return String(v == null ? '' : v)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
  }

  function show(id, msg) {
    var box = el(id);
    if (!box) return;
    box.style.display = 'block';
    box.textContent = msg;
  }

  function hide(id) {
    var box = el(id);
    if (!box) return;
    box.style.display = 'none';
    box.textContent = '';
  }

  function readNumber(obj, keys, def) {
    for (var i = 0; i < keys.length; i++) {
      var k = keys[i];
      if (obj && obj[k] !== undefined && obj[k] !== null && obj[k] !== '') {
        var n = parseFloat(obj[k]);
        if (!isNaN(n)) return n;
      }
    }
    return def || 0;
  }

  function readPositiveNumber(obj, keys, def) {
    for (var i = 0; i < keys.length; i++) {
      var k = keys[i];
      if (obj && obj[k] !== undefined && obj[k] !== null && obj[k] !== '') {
        var n = parseFloat(obj[k]);
        if (!isNaN(n) && n > 0) return n;
      }
    }
    return def || 0;
  }

  function gramFromParts(vori, ana, roti, point) {
    return (
      toNum(vori) * VORI +
      toNum(ana) * ANA +
      toNum(roti) * ROTI +
      toNum(point) * POINT
    );
  }

  function gramToParts(gram) {
    var totalPoint = Math.round((toNum(gram) / VORI) * 960);

    var vori = Math.floor(totalPoint / 960);
    totalPoint = totalPoint % 960;

    var ana = Math.floor(totalPoint / 60);
    totalPoint = totalPoint % 60;

    var roti = Math.floor(totalPoint / 10);
    var point = totalPoint % 10;

    return {
      vori: vori,
      ana: ana,
      roti: roti,
      point: point
    };
  }

  function partsText(parts) {
    return parts.vori + ' ভরি ' + parts.ana + ' আনা ' + parts.roti + ' রতি ' + parts.point + ' পয়েন্ট';
  }

  function calcByValues(vori, ana, roti, point, karat, rate24k, pieces) {
    var gross = gramFromParts(vori, ana, roti, point);
    var ratio = KARAT_RATIO[karat] || 91.667;
    var karatNumber = parseInt(String(karat).replace('K', ''), 10) || 22;
    var pure = gross * ratio / 100;
    var ratePerGram24k = toNum(rate24k) / VORI;
    var total = pure * ratePerGram24k;
    var perPiece = pieces > 0 ? gross / pieces : 0;

    return {
      vori: toNum(vori),
      ana: toNum(ana),
      roti: toNum(roti),
      point: toNum(point),
      gross: gross,
      pure: pure,
      karat: karat,
      karatNumber: karatNumber,
      ratio: ratio,
      rate24k: toNum(rate24k),
      ratePerGram24k: ratePerGram24k,
      total: total,
      pieces: toInt(pieces),
      perPiece: perPiece
    };
  }

  function injectStyle() {
    if (el('newPurFixStyle')) return;

    var style = document.createElement('style');
    style.id = 'newPurFixStyle';
    style.textContent =
      '.party-search-input{width:100%;background:#060E1C;border:1px solid #1A2D50;border-radius:9px;color:#E8F0FE;padding:10px 11px;font-size:14px;outline:none;font-family:inherit;margin-bottom:7px}' +
      '.party-search-input:focus{border-color:rgba(245,184,0,.45)}' +
      '.party-search-input::placeholder{color:#5C7DA8}' +
      '.party-suggest-box{display:none;background:#060E1C;border:1px solid rgba(245,184,0,.35);border-radius:10px;margin:0 0 8px 0;max-height:220px;overflow-y:auto;box-shadow:0 12px 28px rgba(0,0,0,.45);z-index:10050;position:relative}' +
      '.party-suggest-item{padding:11px 12px;border-bottom:1px solid #1A2D50;cursor:pointer;font-size:14px;color:#E8F0FE;background:#060E1C}' +
      '.party-suggest-item:last-child{border-bottom:none}' +
      '.party-suggest-item:active{background:rgba(245,184,0,.14)}' +
      '.party-suggest-name{font-weight:900;color:#F5B800;font-size:14px}' +
      '.party-suggest-phone{font-size:12px;color:#8AA7CF;margin-top:3px}' +
      '.party-suggest-empty{padding:12px;font-size:13px;color:#8AA7CF;text-align:center}' +

      '.sum-val.weight-small{font-size:14px;line-height:1.45;white-space:normal}' +
      '.pur-main-title{font-size:17px;font-weight:900;color:#E8F0FE;margin-bottom:4px}' +
      '.pur-item-line{font-size:12px;color:#F5B800;margin-top:2px}' +
      '.pur-piece-box{display:flex;justify-content:space-between;align-items:center;background:rgba(79,142,247,.08);border:1px solid rgba(79,142,247,.2);border-radius:10px;padding:9px 12px;margin:10px 0;color:#8AA7CF;font-size:13px}' +
      '.pur-piece-box b{color:#F5B800;font-size:17px}' +
      '.pur-weight-break{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:7px;margin:10px 0;padding:10px;border:1px solid rgba(245,184,0,.18);border-radius:11px;background:rgba(245,184,0,.045)}' +
      '.pur-weight-break .wb{background:#060E1C;border:1px solid #1A2D50;border-radius:9px;padding:8px 4px;text-align:center}' +
      '.pur-weight-break .wl{font-size:10px;color:#5C7DA8;margin-bottom:4px;font-weight:700}' +
      '.pur-weight-break .wv{font-size:14px;color:#F5B800;font-weight:900}' +
      '.pur-weight-text{font-size:12px;color:#8AA7CF;margin-top:7px;line-height:1.5}' +

      '.bc-create-btn{padding:8px 12px;background:linear-gradient(135deg,#D4780A,#F5B800);color:#080F1E;border:0;border-radius:9px;font-size:12px;font-weight:900;cursor:pointer;margin-top:8px}' +
      '.bc-create-btn:disabled{opacity:.45;cursor:not-allowed}' +

      '.bcx-summary{background:#060E1C;border:1px solid #1A2D50;border-radius:12px;padding:12px;margin-bottom:12px}' +
      '.bcx-line{display:flex;justify-content:space-between;gap:10px;font-size:12px;color:#8AA7CF;margin-bottom:6px}' +
      '.bcx-line b{color:#F5B800}' +
      '.bcx-row{background:#060E1C;border:1px solid #1A2D50;border-radius:13px;padding:13px;margin-bottom:10px}' +
      '.bcx-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;color:#F5B800;font-weight:900}' +
      '.bcx-del{background:rgba(239,68,68,.12);border:1px solid rgba(239,68,68,.25);color:#EF4444;border-radius:7px;padding:5px 9px;font-size:11px;font-family:inherit}' +
      '.bcx-grid4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:7px}' +
      '.bcx-mini-total{margin-top:9px;padding:8px;background:rgba(245,184,0,.05);border:1px solid rgba(245,184,0,.16);border-radius:8px;color:#8AA7CF;font-size:12px}' +
      '.bcx-mini-total b{color:#F5B800}' +
      '.bcx-result{margin-top:12px}' +
      '.bcx-code{background:rgba(16,185,129,.08);border:1px solid rgba(16,185,129,.2);border-radius:9px;padding:9px;margin-bottom:6px;color:#10B981;font-size:13px;font-weight:800}' +
      '@media(max-width:400px){.bcx-grid4{grid-template-columns:1fr 1fr}}';

    document.head.appendChild(style);
  }

  async function getJson(url) {
    var sep = url.indexOf('?') >= 0 ? '&' : '?';

    var res = await fetch(url + sep + '_t=' + Date.now(), {
      credentials: 'same-origin',
      cache: 'no-store'
    });

    if (res.status === 401 || res.status === 403) {
      window.location.href = 'login.html';
      throw new Error('লগইন প্রয়োজন');
    }

    var text = await res.text();

    try {
      return JSON.parse(text);
    } catch (e) {
      throw new Error('API JSON response দেয়নি');
    }
  }

  function pickArray(res) {
    if (Array.isArray(res)) return res;
    if (res && Array.isArray(res.data)) return res.data;
    if (res && res.data && Array.isArray(res.data.parties)) return res.data.parties;
    if (res && res.data && Array.isArray(res.data.customers)) return res.data.customers;
    if (res && res.data && Array.isArray(res.data.accounts)) return res.data.accounts;
    if (res && res.data && Array.isArray(res.data.purchases)) return res.data.purchases;
    if (res && Array.isArray(res.parties)) return res.parties;
    if (res && Array.isArray(res.customers)) return res.customers;
    if (res && Array.isArray(res.accounts)) return res.accounts;
    if (res && Array.isArray(res.purchases)) return res.purchases;
    if (res && Array.isArray(res.rows)) return res.rows;
    return [];
  }

  async function firstWorking(urls) {
    for (var i = 0; i < urls.length; i++) {
      try {
        var res = await getJson(urls[i]);
        var arr = pickArray(res);
        if (arr.length) return arr;
      } catch (e) {}
    }
    return [];
  }

  async function loadParties() {
    var raw = await firstWorking(API.parties);

    parties = raw.map(function (p) {
      return {
        id: p.id || p.party_id || p.customer_id || p.supplier_id || '',
        name: p.name || p.party_name || p.customer_name || p.supplier_name || p.full_name || '',
        phone: p.phone || p.mobile || p.contact || p.phone_number || '',
        type: p.type || p.party_type || ''
      };
    }).filter(function (p) {
      return p.id && p.name;
    });

    ensureSinglePartyPicker();
    renderSinglePartySelect('');
    enhanceAllMultiPartySelects();
  }

  function getPartyById(id) {
    id = String(id || '');
    for (var i = 0; i < parties.length; i++) {
      if (String(parties[i].id) === id) return parties[i];
    }
    return null;
  }

  function ensureSinglePartyPicker() {
    var select = el('mParty');
    if (!select) return;

    injectStyle();

    if (!el('mPartySearch')) {
      var input = document.createElement('input');
      input.type = 'text';
      input.id = 'mPartySearch';
      input.className = 'party-search-input';
      input.placeholder = 'সাপ্লায়ার নাম / মোবাইল লিখুন...';
      input.autocomplete = 'off';

      select.parentNode.insertBefore(input, select);

      input.addEventListener('input', function () {
        renderSinglePartySuggestions(this.value);
      });

      input.addEventListener('focus', function () {
        renderSinglePartySuggestions(this.value);
      });
    }

    if (!el('mPartySuggest')) {
      var box = document.createElement('div');
      box.id = 'mPartySuggest';
      box.className = 'party-suggest-box';
      select.parentNode.insertBefore(box, select);
    }

    if (!select.dataset.boundSingleParty) {
      select.dataset.boundSingleParty = '1';
      select.addEventListener('change', function () {
        var p = getPartyById(this.value);
        var input = el('mPartySearch');
        if (p && input) input.value = p.name + (p.phone ? ' — ' + p.phone : '');
        hideSinglePartySuggestions();
      });
    }
  }

  function renderSinglePartySelect(keyword) {
    var select = el('mParty');
    if (!select) return;

    var old = select.value;
    var key = String(keyword || '').toLowerCase().trim();

    var list = parties.filter(function (p) {
      var text = (p.name + ' ' + p.phone + ' ' + p.type).toLowerCase();
      return !key || text.indexOf(key) >= 0;
    });

    select.innerHTML = '<option value="">— সাপ্লায়ার বাছাই করুন —</option>';

    list.forEach(function (p) {
      var opt = document.createElement('option');
      opt.value = p.id;
      opt.textContent = p.name + (p.phone ? ' — ' + p.phone : '');
      select.appendChild(opt);
    });

    if (old) select.value = old;
  }

  function renderSinglePartySuggestions(keyword) {
    var box = el('mPartySuggest');
    if (!box) return;

    var key = String(keyword || '').toLowerCase().trim();
    renderSinglePartySelect(key);

    if (!key) {
      box.style.display = 'none';
      box.innerHTML = '';
      return;
    }

    var list = parties.filter(function (p) {
      var text = (p.name + ' ' + p.phone + ' ' + p.type).toLowerCase();
      return text.indexOf(key) >= 0;
    }).slice(0, 25);

    if (!list.length) {
      box.style.display = 'block';
      box.innerHTML = '<div class="party-suggest-empty">কোনো সাপ্লায়ার পাওয়া যায়নি</div>';
      return;
    }

    box.innerHTML = list.map(function (p) {
      return '<div class="party-suggest-item" data-single-party-id="' + esc(p.id) + '">' +
        '<div class="party-suggest-name">' + esc(p.name) + '</div>' +
        '<div class="party-suggest-phone">' + esc(p.phone || 'মোবাইল নেই') + '</div>' +
      '</div>';
    }).join('');

    box.style.display = 'block';
  }

  function hideSinglePartySuggestions() {
    var box = el('mPartySuggest');
    if (box) box.style.display = 'none';
  }

  function selectSingleParty(id) {
    var p = getPartyById(id);
    if (!p) return;

    renderSinglePartySelect('');

    if (el('mParty')) el('mParty').value = p.id;
    if (el('mPartySearch')) el('mPartySearch').value = p.name + (p.phone ? ' — ' + p.phone : '');

    hideSinglePartySuggestions();
  }

  function optionListFromSelect(select) {
    var list = [];

    qsa('option', select).forEach(function (opt) {
      if (!opt.value) return;
      var text = opt.textContent || '';
      var parts = text.split('—');

      list.push({
        id: opt.value,
        name: (parts[0] || text).trim(),
        phone: (parts[1] || '').trim(),
        text: text
      });
    });

    return list;
  }

  function enhanceMultiPartySelect(select) {
    if (!select || select.dataset.multiPartyEnhanced === '1') return;

    injectStyle();

    select.dataset.multiPartyEnhanced = '1';

    var parent = select.parentNode;
    if (!parent) return;

    var input = document.createElement('input');
    input.type = 'text';
    input.className = 'party-search-input multi-party-search';
    input.placeholder = 'সাপ্লায়ার নাম / মোবাইল লিখুন...';
    input.autocomplete = 'off';

    var box = document.createElement('div');
    box.className = 'party-suggest-box multi-party-suggest';

    parent.insertBefore(input, select);
    parent.insertBefore(box, select);

    function getSource() {
      var fromOptions = optionListFromSelect(select);
      if (fromOptions.length) return fromOptions;

      return parties.map(function (p) {
        return {
          id: p.id,
          name: p.name,
          phone: p.phone,
          text: p.name + (p.phone ? ' — ' + p.phone : '')
        };
      });
    }

    function render(keyword) {
      var key = String(keyword || '').toLowerCase().trim();

      if (!key) {
        box.style.display = 'none';
        box.innerHTML = '';
        return;
      }

      var list = getSource().filter(function (p) {
        return (p.name + ' ' + p.phone + ' ' + p.text).toLowerCase().indexOf(key) >= 0;
      }).slice(0, 25);

      if (!list.length) {
        box.style.display = 'block';
        box.innerHTML = '<div class="party-suggest-empty">কোনো সাপ্লায়ার পাওয়া যায়নি</div>';
        return;
      }

      box.innerHTML = list.map(function (p) {
        return '<div class="party-suggest-item" data-multi-party-id="' + esc(p.id) + '">' +
          '<div class="party-suggest-name">' + esc(p.name) + '</div>' +
          '<div class="party-suggest-phone">' + esc(p.phone || 'মোবাইল নেই') + '</div>' +
        '</div>';
      }).join('');

      box.style.display = 'block';
    }

    input.addEventListener('input', function () {
      render(this.value);
    });

    input.addEventListener('focus', function () {
      render(this.value);
    });

    box.addEventListener('click', function (e) {
      var item = e.target.closest ? e.target.closest('.party-suggest-item') : null;
      if (!item) return;

      var id = item.getAttribute('data-multi-party-id');
      var source = getSource();
      var found = null;

      source.forEach(function (p) {
        if (String(p.id) === String(id)) found = p;
      });

      if (!found) return;

      var exists = false;
      qsa('option', select).forEach(function (opt) {
        if (String(opt.value) === String(found.id)) exists = true;
      });

      if (!exists) {
        var opt = document.createElement('option');
        opt.value = found.id;
        opt.textContent = found.name + (found.phone ? ' — ' + found.phone : '');
        select.appendChild(opt);
      }

      select.value = found.id;
      input.value = found.name + (found.phone ? ' — ' + found.phone : '');
      box.style.display = 'none';

      try {
        select.dispatchEvent(new Event('change', { bubbles: true }));
      } catch (err) {}
    });
  }

  function enhanceAllMultiPartySelects() {
    qsa('.row-party-sel').forEach(enhanceMultiPartySelect);
  }

  async function loadAccounts() {
    var raw = await firstWorking(API.accounts);

    accounts = raw.map(function (a) {
      return {
        id: a.id || a.account_id || a.cash_account_id || '',
        name: a.account_name || a.name || a.title || '',
        balance: a.current_balance || a.balance || 0
      };
    }).filter(function (a) {
      return a.id && a.name;
    });

    renderAccount('mCashAcc');
    renderAccount('mCashAcc2');
  }

  function renderAccount(id) {
    var select = el(id);
    if (!select) return;

    var old = select.value;
    select.innerHTML = '';

    accounts.forEach(function (a) {
      var opt = document.createElement('option');
      opt.value = a.id;
      opt.textContent = a.name + ' (' + money(a.balance) + ')';
      select.appendChild(opt);
    });

    if (old) select.value = old;
  }

  function calcSingle() {
    var c = calcByValues(
      toNum(el('wVori') ? el('wVori').value : 0),
      toNum(el('wAna') ? el('wAna').value : 0),
      toNum(el('wRoti') ? el('wRoti').value : 0),
      toNum(el('wPoint') ? el('wPoint').value : 0),
      el('mKarat') ? el('mKarat').value : '22K',
      toNum(el('mRate') ? el('mRate').value : 0),
      toInt(el('mPieces') ? el('mPieces').value : 1) || 1
    );

    if (el('wGram')) el('wGram').textContent = c.gross.toFixed(3);
    if (el('wVoriShow')) el('wVoriShow').textContent = c.vori;
    if (el('wAnaShow')) el('wAnaShow').textContent = c.ana;
    if (el('wRotiShow')) el('wRotiShow').textContent = c.roti;
    if (el('wPointShow')) el('wPointShow').textContent = c.point;

    if (el('cRatio')) el('cRatio').textContent = c.ratio.toFixed(2) + '%';
    if (el('cGross')) el('cGross').textContent = c.gross.toFixed(3) + ' গ্রাম';
    if (el('cPure')) el('cPure').textContent = c.pure.toFixed(3) + ' গ্রাম';
    if (el('cRateG')) el('cRateG').textContent = money(c.ratePerGram24k) + '/গ্রাম';
    if (el('cWpp')) el('cWpp').textContent = c.perPiece.toFixed(2) + ' গ্রাম/পিস';
    if (el('cTotal')) el('cTotal').textContent = money(c.total);

    return c;
  }

  function buildPayload(row) {
    var ratioFixed = Number(row.ratio.toFixed(3));

    return {
      purchase_date: row.purchaseDate,
      date: row.purchaseDate,

      item_name: row.itemName,
      name: row.itemName,

      party_id: row.partyId,
      supplier_id: row.partyId,
      customer_id: row.partyId,

      purity_type: 'system',
      selected_purity_type: 'system',

      system_purity: ratioFixed,
      system_purity_percent: ratioFixed,
      system_purity_value: ratioFixed,
      system_purity_karat: row.karatNumber,
      system_purity_label: row.karat,

      actual_purity: ratioFixed,
      actual_purity_percent: ratioFixed,
      actual_purity_value: ratioFixed,

      purity: row.karat,
      karat: row.karat,
      karat_value: row.karatNumber,
      karat_ratio: ratioFixed,
      purity_percent: ratioFixed,

      total_pieces: row.pieces,
      pieces: row.pieces,
      qty: row.pieces,
      piece_count: row.pieces,
      total_piece: row.pieces,
      total_pcs: row.pieces,
      pcs: row.pieces,

      location_id: row.locationId,

      total_weight_gram: Number(row.gross.toFixed(3)),
      gross_weight: Number(row.gross.toFixed(3)),
      gross_weight_gram: Number(row.gross.toFixed(3)),
      weight_gram: Number(row.gross.toFixed(3)),

      pure_weight_gram: Number(row.pure.toFixed(3)),
      pure_weight: Number(row.pure.toFixed(3)),
      pure_gold_gram: Number(row.pure.toFixed(3)),

      vori: row.vori,
      bhori: row.vori,
      ana: row.ana,
      roti: row.roti,
      rati: row.roti,
      point: row.point,

      rate_24k: row.rate24k,
      rate24k: row.rate24k,
      gold_rate_24k: row.rate24k,
      rate_per_vori_24k: row.rate24k,
      rate_per_vori: row.rate24k,
      gold_rate: row.rate24k,
      rate: row.rate24k,

      rate_per_gram_24k: Number(row.ratePerGram24k.toFixed(4)),
      rate_per_gram: Number(row.ratePerGram24k.toFixed(4)),

      total_amount: Number(row.total.toFixed(2)),
      amount: Number(row.total.toFixed(2)),
      paid_amount: Number(row.total.toFixed(2)),
      payable_amount: Number(row.total.toFixed(2)),

      payment_method_id: row.paymentMethodId,
      cash_account_id: row.cashAccountId,
      account_id: row.cashAccountId,

      note: row.note
    };
  }

  async function postPurchase(payload) {
    var res = await fetch(API.addPurchase + '?_t=' + Date.now(), {
      method: 'POST',
      credentials: 'same-origin',
      cache: 'no-store',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify(payload)
    });

    var text = await res.text();

    try {
      return JSON.parse(text);
    } catch (e) {
      return { success: false, message: 'API JSON response দেয়নি' };
    }
  }

  function openSingleModal() {
    hide('mOk');
    hide('mEr');

    if (el('mDate') && !el('mDate').value) el('mDate').value = today;

    loadParties();
    loadAccounts();
    calcSingle();

    if (el('purModal')) el('purModal').classList.add('show');
  }

  function closeSingleModal() {
    if (el('purModal')) el('purModal').classList.remove('show');
  }

  async function saveSinglePurchase() {
    hide('mOk');
    hide('mEr');

    var c = calcSingle();

    var purchaseDate = el('mDate') ? el('mDate').value : today;
    var itemName = (el('mItemName') ? el('mItemName').value : '').trim() || 'আইটেম নাম নেই';
    var partyId = el('mParty') && el('mParty').value ? toInt(el('mParty').value) : null;
    var locationId = toInt(el('mLocation') ? el('mLocation').value : 1) || 1;
    var paymentMethodId = toInt(el('mPayment') ? el('mPayment').value : 1) || 1;
    var cashAccountId = toInt(el('mCashAcc') ? el('mCashAcc').value : 0);
    var note = (el('mNote') ? el('mNote').value : '').trim();

    if (c.rate24k <= 0) {
      show('mEr', 'সঠিক 24K রেট দিন');
      return;
    }

    if (c.gross <= 0) {
      show('mEr', 'সঠিক ওজন দিন');
      return;
    }

    if (c.pieces <= 0) {
      show('mEr', 'সঠিক পিস সংখ্যা দিন');
      return;
    }

    if (!cashAccountId) {
      show('mEr', 'ক্যাশ অ্যাকাউন্ট বাছাই করুন');
      return;
    }

    var btn = el('mBtn');
    if (btn) {
      btn.disabled = true;
      btn.textContent = 'সেভ হচ্ছে...';
    }

    var payload = buildPayload({
      purchaseDate: purchaseDate,
      itemName: itemName,
      partyId: partyId,
      locationId: locationId,
      paymentMethodId: paymentMethodId,
      cashAccountId: cashAccountId,
      note: note,

      vori: c.vori,
      ana: c.ana,
      roti: c.roti,
      point: c.point,
      gross: c.gross,
      pure: c.pure,
      karat: c.karat,
      karatNumber: c.karatNumber,
      ratio: c.ratio,
      rate24k: c.rate24k,
      ratePerGram24k: c.ratePerGram24k,
      total: c.total,
      pieces: c.pieces
    });

    try {
      var data = await postPurchase(payload);

      if (data.success === true || data.status === true || data.ok === true) {
        show('mOk', '✅ ক্রয় সফলভাবে সেভ হয়েছে');
        setTimeout(function () {
          closeSingleModal();
          window.location.href = 'new_purchase.html?v=saved' + Date.now();
        }, 900);
      } else {
        show('mEr', data.message || data.error || 'ক্রয় সেভ হয়নি');
      }
    } catch (err) {
      show('mEr', 'সেভ সমস্যা: ' + err.message);
    } finally {
      if (btn) {
        btn.disabled = false;
        btn.textContent = '💾 ক্রয় সেভ করুন';
      }
    }
  }

  /* =====================================================
     Multi Entry Override
     ===================================================== */

  function openMultiModal() {
    ensureMultiModal();

    if (el('multiRows')) el('multiRows').innerHTML = '';
    multiRowCount = 0;

    if (el('mDate2')) el('mDate2').value = today;
    if (el('multiOk')) el('multiOk').style.display = 'none';
    if (el('multiEr')) el('multiEr').style.display = 'none';

    loadParties();
    loadAccounts();

    addMultiRow();

    if (el('multiModal')) el('multiModal').classList.add('show');
  }

  function closeMultiModal() {
    if (el('multiModal')) el('multiModal').classList.remove('show');
  }

  function ensureMultiModal() {
    if (el('multiModal')) return;

    var div = document.createElement('div');
    div.id = 'multiModal';
    div.className = 'modal';
    div.innerHTML =
      '<div class="mbox purple-top">' +
        '<div class="mtitle purple">📋 মাল্টি ক্রয় এন্ট্রি</div>' +
        '<div class="aok" id="multiOk"></div>' +
        '<div class="aer" id="multiEr"></div>' +

        '<div class="multi-common">' +
          '<div class="multi-common-title">সকল এন্ট্রির জন্য সাধারণ তথ্য</div>' +
          '<div class="row2" style="margin-bottom:8px">' +
            '<div class="rf"><label>তারিখ</label><input type="date" id="mDate2"></div>' +
            '<div class="rf"><label>রেট (প্রতি ভরি)</label><input type="number" id="mRate2" placeholder="০" step="1" min="0"></div>' +
          '</div>' +
          '<div class="row2" style="margin-bottom:8px">' +
            '<div class="rf"><label>লোকেশন</label>' +
              '<select id="mLocation2">' +
                '<option value="1">ফ্যাক্টরি</option>' +
                '<option value="2">শোরুম-১</option>' +
                '<option value="3">শোরুম-২</option>' +
                '<option value="4">লকার</option>' +
              '</select>' +
            '</div>' +
            '<div class="rf"><label>পেমেন্ট পদ্ধতি</label>' +
              '<select id="mPayment2">' +
                '<option value="1">নগদ</option>' +
                '<option value="2">ব্যাংক</option>' +
                '<option value="3">বিকাশ/নগদ</option>' +
                '<option value="4">কার্ড</option>' +
                '<option value="5">চেক</option>' +
              '</select>' +
            '</div>' +
          '</div>' +
          '<div class="rf"><label>ক্যাশ অ্যাকাউন্ট</label><select id="mCashAcc2"></select></div>' +
        '</div>' +

        '<div id="multiRows"></div>' +
        '<button class="btn-add-row" id="addRowBtn">+ আরেকটি এন্ট্রি যোগ করুন</button>' +

        '<div class="multi-total">' +
          '<div class="multi-total-lbl">মোট পরিশোধ</div>' +
          '<div class="multi-total-amt" id="multiTotalAmt">৳০</div>' +
          '<div class="multi-total-cnt" id="multiTotalCnt">০টি এন্ট্রি | ০ পিস | ০.০০০ গ্রাম</div>' +
        '</div>' +

        '<div class="mbtns">' +
          '<button class="bcl" id="multiCancelBtn">বাতিল</button>' +
          '<button class="bsv purple" id="multiSaveBtn">✅ সব সেভ করুন</button>' +
        '</div>' +
      '</div>';

    document.body.appendChild(div);
  }

  function partyOptionsHtml() {
    var html = '<option value="">— সাপ্লায়ার —</option>';
    parties.forEach(function (p) {
      html += '<option value="' + esc(p.id) + '">' + esc(p.name + (p.phone ? ' — ' + p.phone : '')) + '</option>';
    });
    return html;
  }

  function addMultiRow() {
    ensureMultiModal();

    multiRowCount++;
    var n = multiRowCount;

    var div = document.createElement('div');
    div.className = 'entry-row';
    div.id = 'mr-' + n;

    div.innerHTML =
      '<div class="row-head">' +
        '<span class="row-num">📌 আইটেম ' + n + '</span>' +
        (n > 1 ? '<button class="row-del" data-multi-del="' + n + '">✕ বাদ দিন</button>' : '') +
      '</div>' +

      '<div class="row2" style="margin-bottom:8px">' +
        '<div class="rf"><label>আইটেমের নাম</label>' +
          '<input type="text" id="rname' + n + '" placeholder="চেইন, আংটি..."></div>' +
        '<div class="rf"><label>পিস সংখ্যা</label>' +
          '<input type="number" id="rpc' + n + '" value="1" min="1" step="1" data-multi-calc="' + n + '"></div>' +
      '</div>' +

      '<div class="row2" style="margin-bottom:8px">' +
        '<div class="rf"><label>সাপ্লায়ার</label>' +
          '<select class="row-party-sel" id="rp' + n + '">' + partyOptionsHtml() + '</select></div>' +
        '<div class="rf"><label>ক্যারেট</label>' +
          '<select id="rk' + n + '" data-multi-calc="' + n + '">' +
            '<option value="24K">24K</option>' +
            '<option value="22K" selected>22K</option>' +
            '<option value="21K">21K</option>' +
            '<option value="18K">18K</option>' +
            '<option value="other">অন্যান্য</option>' +
          '</select></div>' +
      '</div>' +

      '<div class="bcx-grid4" style="margin-bottom:8px">' +
        '<div class="rf"><label>ভরি</label><input type="number" id="rv' + n + '" placeholder="0" min="0" step="1" data-multi-calc="' + n + '"></div>' +
        '<div class="rf"><label>আনা</label><input type="number" id="ra' + n + '" placeholder="0" min="0" step="1" data-multi-calc="' + n + '"></div>' +
        '<div class="rf"><label>রতি</label><input type="number" id="rr' + n + '" placeholder="0" min="0" step="1" data-multi-calc="' + n + '"></div>' +
        '<div class="rf"><label>পয়েন্ট</label><input type="number" id="rpt' + n + '" placeholder="0" min="0" step="1" data-multi-calc="' + n + '"></div>' +
      '</div>' +

      '<div class="rf" style="margin-bottom:8px"><label>নোট</label>' +
        '<input type="text" id="rn' + n + '" placeholder="বিশেষ তথ্য..."></div>' +

      '<div class="row-calc">' +
        'ওজন: <span id="rgram' + n + '">০g</span>' +
        '&nbsp;|&nbsp; পিস: <span id="rpcs' + n + '">১ পিস</span>' +
        '&nbsp;|&nbsp; মোট: <span id="ramt' + n + '">৳০</span>' +
      '</div>';

    el('multiRows').appendChild(div);
    enhanceAllMultiPartySelects();
    calcMultiRow(n);
  }

  function removeMultiRow(n) {
    var row = el('mr-' + n);
    if (row) row.remove();
    calcMultiTotal();
  }

  function calcMultiRow(n) {
    var rate = toNum(el('mRate2') ? el('mRate2').value : 0);
    var c = calcByValues(
      toNum(el('rv' + n) ? el('rv' + n).value : 0),
      toNum(el('ra' + n) ? el('ra' + n).value : 0),
      toNum(el('rr' + n) ? el('rr' + n).value : 0),
      toNum(el('rpt' + n) ? el('rpt' + n).value : 0),
      el('rk' + n) ? el('rk' + n).value : '22K',
      rate,
      toInt(el('rpc' + n) ? el('rpc' + n).value : 1) || 1
    );

    if (el('rgram' + n)) el('rgram' + n).textContent = c.gross.toFixed(3) + 'g';
    if (el('rpcs' + n)) el('rpcs' + n).textContent = c.pieces + ' পিস';
    if (el('ramt' + n)) el('ramt' + n).textContent = money(c.total);

    calcMultiTotal();
  }

  function calcMultiTotal() {
    var rows = el('multiRows') ? qsa('.entry-row', el('multiRows')) : [];
    var rate = toNum(el('mRate2') ? el('mRate2').value : 0);

    var totalAmt = 0;
    var totalPieces = 0;
    var totalGross = 0;

    rows.forEach(function (row) {
      var n = row.id.replace('mr-', '');
      var c = calcByValues(
        toNum(el('rv' + n) ? el('rv' + n).value : 0),
        toNum(el('ra' + n) ? el('ra' + n).value : 0),
        toNum(el('rr' + n) ? el('rr' + n).value : 0),
        toNum(el('rpt' + n) ? el('rpt' + n).value : 0),
        el('rk' + n) ? el('rk' + n).value : '22K',
        rate,
        toInt(el('rpc' + n) ? el('rpc' + n).value : 1) || 1
      );

      totalAmt += c.total;
      totalPieces += c.pieces;
      totalGross += c.gross;
    });

    if (el('multiTotalAmt')) el('multiTotalAmt').textContent = money(totalAmt);
    if (el('multiTotalCnt')) {
      var parts = gramToParts(totalGross);
      el('multiTotalCnt').textContent =
        rows.length + 'টি এন্ট্রি | ' +
        totalPieces + ' পিস | ' +
        partsText(parts) + ' | ' +
        totalGross.toFixed(3) + ' গ্রাম';
    }
  }

  async function saveMultiEntries() {
    var er = el('multiEr');
    var ok = el('multiOk');
    var btn = el('multiSaveBtn');

    if (er) { er.style.display = 'none'; er.textContent = ''; }
    if (ok) { ok.style.display = 'none'; ok.textContent = ''; }

    var rate24k = toNum(el('mRate2') ? el('mRate2').value : 0);
    var purchaseDate = el('mDate2') ? (el('mDate2').value || today) : today;
    var cashAccountId = toInt(el('mCashAcc2') ? el('mCashAcc2').value : 0);
    var paymentMethodId = toInt(el('mPayment2') ? el('mPayment2').value : 1) || 1;
    var locationId = toInt(el('mLocation2') ? el('mLocation2').value : 1) || 1;

    if (rate24k <= 0) {
      if (er) { er.style.display = 'block'; er.textContent = 'সঠিক 24K রেট দিন'; }
      return;
    }

    if (!cashAccountId) {
      if (er) { er.style.display = 'block'; er.textContent = 'ক্যাশ অ্যাকাউন্ট বাছাই করুন'; }
      return;
    }

    var rows = el('multiRows') ? qsa('.entry-row', el('multiRows')) : [];
    var entries = [];
    var hasError = false;

    rows.forEach(function (row) {
      var n = row.id.replace('mr-', '');

      var itemName = (el('rname' + n) ? el('rname' + n).value : '').trim() || 'আইটেম ' + n;
      var pieces = toInt(el('rpc' + n) ? el('rpc' + n).value : 1) || 1;
      var partyId = el('rp' + n) && el('rp' + n).value ? toInt(el('rp' + n).value) : null;
      var karat = el('rk' + n) ? el('rk' + n).value : '22K';
      var vori = toNum(el('rv' + n) ? el('rv' + n).value : 0);
      var ana = toNum(el('ra' + n) ? el('ra' + n).value : 0);
      var roti = toNum(el('rr' + n) ? el('rr' + n).value : 0);
      var point = toNum(el('rpt' + n) ? el('rpt' + n).value : 0);
      var note = (el('rn' + n) ? el('rn' + n).value : '').trim();

      var c = calcByValues(vori, ana, roti, point, karat, rate24k, pieces);

      if (c.gross <= 0) {
        hasError = true;
        return;
      }

      entries.push(buildPayload({
        purchaseDate: purchaseDate,
        itemName: itemName,
        partyId: partyId,
        locationId: locationId,
        paymentMethodId: paymentMethodId,
        cashAccountId: cashAccountId,
        note: note,

        vori: c.vori,
        ana: c.ana,
        roti: c.roti,
        point: c.point,
        gross: c.gross,
        pure: c.pure,
        karat: c.karat,
        karatNumber: c.karatNumber,
        ratio: c.ratio,
        rate24k: c.rate24k,
        ratePerGram24k: c.ratePerGram24k,
        total: c.total,
        pieces: c.pieces
      }));
    });

    if (hasError) {
      if (er) { er.style.display = 'block'; er.textContent = 'সব এন্ট্রিতে সঠিক ওজন দিন'; }
      return;
    }

    if (!entries.length) {
      if (er) { er.style.display = 'block'; er.textContent = 'কমপক্ষে একটি এন্ট্রি দিন'; }
      return;
    }

    if (btn) {
      btn.disabled = true;
      btn.textContent = 'সেভ হচ্ছে...';
    }

    var success = 0;
    var failed = 0;
    var lastError = '';

    for (var i = 0; i < entries.length; i++) {
      try {
        var data = await postPurchase(entries[i]);
        if (data.success === true || data.status === true || data.ok === true) {
          success++;
        } else {
          failed++;
          lastError = data.message || data.error || 'ক্রয় সেভ হয়নি';
        }
      } catch (e) {
        failed++;
        lastError = e.message;
      }
    }

    if (btn) {
      btn.disabled = false;
      btn.textContent = '✅ সব সেভ করুন';
    }

    if (failed === 0) {
      if (ok) {
        ok.style.display = 'block';
        ok.textContent = '✅ ' + success + 'টি ক্রয় সফলভাবে সেভ হয়েছে';
      }

      setTimeout(function () {
        window.location.href = 'new_purchase.html?v=multisaved' + Date.now();
      }, 900);
    } else {
      if (er) {
        er.style.display = 'block';
        er.textContent = '⚠️ ' + success + 'টি সফল, ' + failed + 'টি ব্যর্থ — ' + lastError;
      }
    }
  }

  /* =====================================================
     Purchase List
     ===================================================== */

  function getWeightParts(row, gross) {
    var vori = readNumber(row, ['vori', 'bhori', 'total_vori', 'weight_vori'], 0);
    var ana = readNumber(row, ['ana', 'aana', 'total_ana', 'weight_ana'], 0);
    var roti = readNumber(row, ['roti', 'rati', 'total_roti', 'total_rati', 'weight_roti'], 0);
    var point = readNumber(row, ['point', 'points', 'total_point', 'weight_point'], 0);

    if (vori > 0 || ana > 0 || roti > 0 || point > 0) {
      return { vori: vori, ana: ana, roti: roti, point: point };
    }

    return gramToParts(gross);
  }

  function normalizePurchase(p) {
    var gross = readPositiveNumber(p, [
      'total_weight_gram',
      'gross_weight_gram',
      'gross_weight',
      'weight_gram',
      'net_weight_gram',
      'net_weight',
      'total_gram',
      'gram',
      'grams'
    ], 0);

    var pure = readPositiveNumber(p, [
      'pure_weight_gram',
      'pure_weight',
      'pure_gold_gram',
      'pure_gram'
    ], 0);

    var pieces = readPositiveNumber(p, [
      'total_pieces',
      'total_piece',
      'pieces',
      'piece',
      'pcs',
      'total_pcs',
      'qty',
      'quantity',
      'piece_count',
      'item_piece',
      'item_pieces',
      'total_qty'
    ], 0);

    var parts = getWeightParts(p, gross);

    var barcodeDone = readNumber(p, [
      'barcode_created_pieces',
      'barcode_done',
      'barcode_pieces',
      'created_barcode',
      'barcode_count'
    ], 0);

    var remainingApi = readNumber(p, [
      'remaining_pieces',
      'barcode_remaining',
      'pending_pieces',
      'remaining_piece'
    ], -1);

    var remaining = remainingApi >= 0 ? remainingApi : Math.max(0, pieces - barcodeDone);

    var partyName = p.party_name || p.supplier_name || p.customer_name || p.supplier || '';
    var itemName = p.item_name || p.name || p.product_name || p.item || '';

    return {
      id: p.id || p.purchase_id || '',
      date: p.purchase_date || p.date || p.created_at || '',
      item: itemName,
      party: partyName,
      karat: p.karat || p.purity || p.system_purity_label || '22K',
      pieces: pieces,
      gross: gross,
      pure: pure,
      amount: readPositiveNumber(p, ['total_amount', 'amount', 'paid_amount', 'payable_amount'], 0),
      location: p.location_name || p.location || p.stock_location_name || '',
      location_id: readNumber(p, ['location_id', 'stock_location_id'], 0),
      remaining: remaining,
      parts: parts
    };
  }

  async function loadPurchases() {
    var from = el('fromDate') ? el('fromDate').value : '';
    var to = el('toDate') ? el('toDate').value : '';

    var urls = API.purchases.map(function (u) {
      var sep = u.indexOf('?') >= 0 ? '&' : '?';
      return u + sep + 'from_date=' + encodeURIComponent(from) + '&to_date=' + encodeURIComponent(to);
    });

    try {
      var raw = await firstWorking(urls);
      purchases = raw.map(normalizePurchase);
      renderPurchaseList();
      updateSummary();
    } catch (e) {
      if (el('purList')) el('purList').innerHTML = '<div class="empty">ক্রয় তালিকা লোড হয়নি</div>';
    }
  }

  function renderPurchaseList() {
    var box = el('purList');
    if (!box) return;

    injectStyle();

    if (!purchases.length) {
      box.innerHTML = '<div class="empty">কোনো ক্রয় পাওয়া যায়নি</div>';
      return;
    }

    box.innerHTML = purchases.map(function (p) {
      var kClass = 'k-other';
      if (p.karat === '24K') kClass = 'k-24';
      if (p.karat === '22K') kClass = 'k-22';
      if (p.karat === '21K') kClass = 'k-21';
      if (p.karat === '18K') kClass = 'k-18';

      var title = p.party || 'সাপ্লায়ার নেই';
      var itemLine = p.item && p.item !== 'নাম নেই' ? p.item : 'আইটেম নাম নেই';
      var btnDisabled = p.remaining <= 0 ? 'disabled' : '';

      return '' +
        '<div class="pur-card" data-purchase-id="' + esc(p.id) + '">' +

          '<div class="pur-top">' +
            '<div>' +
              '<div class="pur-main-title">' + esc(title) + '</div>' +
              '<div class="pur-item-line">আইটেম: ' + esc(itemLine) + '</div>' +
              '<div class="pur-date">' + esc(p.date) + '</div>' +
            '</div>' +
            '<div class="pur-karat ' + kClass + '">' + esc(p.karat) + '</div>' +
          '</div>' +

          '<div class="pur-piece-box">' +
            '<span>মোট পিস</span>' +
            '<b>' + esc(p.pieces) + ' পিস</b>' +
          '</div>' +

          '<div class="pur-details">' +
            '<div class="pur-detail"><div class="dl">গ্রস</div><div class="dv">' + p.gross.toFixed(3) + 'g</div></div>' +
            '<div class="pur-detail"><div class="dl">বিশুদ্ধ</div><div class="dv">' + p.pure.toFixed(3) + 'g</div></div>' +
            '<div class="pur-detail"><div class="dl">বাকি</div><div class="dv">' + p.remaining + ' পিস</div></div>' +
          '</div>' +

          '<div class="pur-weight-break">' +
            '<div class="wb"><div class="wl">ভরি</div><div class="wv">' + esc(p.parts.vori) + '</div></div>' +
            '<div class="wb"><div class="wl">আনা</div><div class="wv">' + esc(p.parts.ana) + '</div></div>' +
            '<div class="wb"><div class="wl">রতি</div><div class="wv">' + esc(p.parts.roti) + '</div></div>' +
            '<div class="wb"><div class="wl">পয়েন্ট</div><div class="wv">' + esc(p.parts.point) + '</div></div>' +
          '</div>' +

          '<div class="pur-weight-text">মোট ওজন: ' + esc(partsText(p.parts)) + '</div>' +

          '<div class="pur-bottom">' +
            '<div>' +
              '<div class="pur-amount">' + money(p.amount) + '</div>' +
              '<div class="pur-loc">' + esc(p.location || 'লোকেশন নেই') + '</div>' +
            '</div>' +
            '<div class="pur-actions">' +
              '<div class="pur-loc">বারকোড বাকি: ' + p.remaining + ' পিস</div>' +
              '<button class="bc-create-btn" data-bc-open="' + esc(p.id) + '" ' + btnDisabled + '>🏷️ বারকোড তৈরি</button>' +
            '</div>' +
          '</div>' +

        '</div>';
    }).join('');
  }

  function updateSummary() {
    var count = 0;
    var amount = 0;
    var gross = 0;
    var pieces = 0;

    purchases.forEach(function (p) {
      var d = String(p.date || '').slice(0, 10);

      if (!p.date || d === today) {
        count++;
        amount += p.amount;
        gross += p.gross;
        pieces += p.pieces;
      }
    });

    var parts = gramToParts(gross);

    if (el('sumEntries')) el('sumEntries').textContent = count;
    if (el('sumAmount')) el('sumAmount').textContent = money(amount);

    if (el('sumGross')) {
      el('sumGross').classList.add('weight-small');
      el('sumGross').textContent = partsText(parts);
    }

    if (el('sumPieces')) el('sumPieces').textContent = pieces;
  }

  function getPurchaseById(id) {
    id = String(id || '');
    for (var i = 0; i < purchases.length; i++) {
      if (String(purchases[i].id) === id) return purchases[i];
    }
    return null;
  }

  /* =====================================================
     Manual Barcode Create
     ===================================================== */

  function ensureBarcodeModal() {
    if (el('manualBcModal')) return;

    var div = document.createElement('div');
    div.id = 'manualBcModal';
    div.className = 'modal';
    div.innerHTML =
      '<div class="mbox">' +
        '<div class="mtitle">🏷️ বারকোড তৈরি</div>' +
        '<div class="aok" id="bcxOk"></div>' +
        '<div class="aer" id="bcxEr"></div>' +

        '<div class="bcx-summary" id="bcxSummary"></div>' +

        '<div id="bcxRows"></div>' +

        '<button class="btn-add-row" id="bcxAddRowBtn">+ আরেকটি বারকোড যোগ করুন</button>' +

        '<div class="bcx-summary" id="bcxLiveTotal"></div>' +

        '<div class="mbtns">' +
          '<button class="bcl" id="bcxCancelBtn">বাতিল</button>' +
          '<button class="bsv" id="bcxSaveBtn">✅ বারকোড সেভ করুন</button>' +
        '</div>' +

        '<div class="bcx-result" id="bcxResult"></div>' +
      '</div>';

    document.body.appendChild(div);
  }

  function openBarcodeModal(purchaseId) {
    ensureBarcodeModal();

    var p = getPurchaseById(purchaseId);
    if (!p) {
      alert('ক্রয় এন্ট্রি পাওয়া যায়নি');
      return;
    }

    currentBarcodePurchase = p;
    barcodeRowCount = 0;

    hide('bcxOk');
    hide('bcxEr');

    if (el('bcxResult')) el('bcxResult').innerHTML = '';
    if (el('bcxRows')) el('bcxRows').innerHTML = '';

    renderBarcodeSummary();
    addBarcodeRow();

    el('manualBcModal').classList.add('show');
  }

  function closeBarcodeModal() {
    if (el('manualBcModal')) el('manualBcModal').classList.remove('show');
  }

  function renderBarcodeSummary() {
    var p = currentBarcodePurchase;
    if (!p || !el('bcxSummary')) return;

    el('bcxSummary').innerHTML =
      '<div class="bcx-line"><span>সাপ্লায়ার</span><b>' + esc(p.party || 'সাপ্লায়ার নেই') + '</b></div>' +
      '<div class="bcx-line"><span>আইটেম</span><b>' + esc(p.item || 'আইটেম নাম নেই') + '</b></div>' +
      '<div class="bcx-line"><span>ক্যারেট</span><b>' + esc(p.karat) + '</b></div>' +
      '<div class="bcx-line"><span>ক্রয়ের মোট পিস</span><b>' + esc(p.pieces) + ' পিস</b></div>' +
      '<div class="bcx-line"><span>বারকোড বাকি</span><b>' + esc(p.remaining) + ' পিস</b></div>' +
      '<div class="bcx-line"><span>ক্রয়ের মোট ওজন</span><b>' + esc(partsText(p.parts)) + '</b></div>' +
      '<div class="bcx-line"><span>গ্রাম</span><b>' + p.gross.toFixed(3) + 'g</b></div>';
  }

  function addBarcodeRow() {
    if (!currentBarcodePurchase) return;

    if (currentBarcodePurchase.remaining > 0) {
      var currentRows = el('bcxRows') ? qsa('.bcx-row', el('bcxRows')).length : 0;
      if (currentRows >= currentBarcodePurchase.remaining) {
        show('bcxEr', 'বাকি পিসের বেশি বারকোড যোগ করা যাবে না');
        return;
      }
    }

    barcodeRowCount++;
    var n = barcodeRowCount;
    var p = currentBarcodePurchase;

    var div = document.createElement('div');
    div.className = 'bcx-row';
    div.id = 'bcxRow' + n;

    div.innerHTML =
      '<div class="bcx-head">' +
        '<span>বারকোড আইটেম ' + n + '</span>' +
        (n > 1 ? '<button class="bcx-del" data-bcx-del="' + n + '">✕ বাদ দিন</button>' : '') +
      '</div>' +

      '<div class="row2" style="margin-bottom:8px">' +
        '<div class="rf"><label>আইটেম নাম</label><input type="text" id="bcxName' + n + '" value="' + esc(p.item || '') + '" placeholder="আইটেম নাম"></div>' +
        '<div class="rf"><label>ক্যারেট</label>' +
          '<select id="bcxKarat' + n + '">' +
            '<option value="24K">24K</option>' +
            '<option value="22K">22K</option>' +
            '<option value="21K">21K</option>' +
            '<option value="18K">18K</option>' +
            '<option value="other">অন্যান্য</option>' +
          '</select>' +
        '</div>' +
      '</div>' +

      '<div class="bcx-grid4">' +
        '<div class="rf"><label>ভরি</label><input type="number" id="bcxVori' + n + '" min="0" step="1" placeholder="0" data-bcx-calc="' + n + '"></div>' +
        '<div class="rf"><label>আনা</label><input type="number" id="bcxAna' + n + '" min="0" step="1" placeholder="0" data-bcx-calc="' + n + '"></div>' +
        '<div class="rf"><label>রতি</label><input type="number" id="bcxRoti' + n + '" min="0" step="1" placeholder="0" data-bcx-calc="' + n + '"></div>' +
        '<div class="rf"><label>পয়েন্ট</label><input type="number" id="bcxPoint' + n + '" min="0" step="1" placeholder="0" data-bcx-calc="' + n + '"></div>' +
      '</div>' +

      '<div class="rf" style="margin-top:8px"><label>নোট</label><input type="text" id="bcxNote' + n + '" placeholder="ঐচ্ছিক নোট"></div>' +

      '<div class="bcx-mini-total" id="bcxMini' + n + '">ওজন: <b>০.০০০g</b></div>';

    el('bcxRows').appendChild(div);

    if (el('bcxKarat' + n)) el('bcxKarat' + n).value = p.karat || '22K';

    updateBarcodeRow(n);
    updateBarcodeLiveTotal();
  }

  function removeBarcodeRow(n) {
    var row = el('bcxRow' + n);
    if (row) row.remove();
    updateBarcodeLiveTotal();
  }

  function updateBarcodeRow(n) {
    var gross = gramFromParts(
      toNum(el('bcxVori' + n) ? el('bcxVori' + n).value : 0),
      toNum(el('bcxAna' + n) ? el('bcxAna' + n).value : 0),
      toNum(el('bcxRoti' + n) ? el('bcxRoti' + n).value : 0),
      toNum(el('bcxPoint' + n) ? el('bcxPoint' + n).value : 0)
    );

    if (el('bcxMini' + n)) {
      var parts = gramToParts(gross);
      el('bcxMini' + n).innerHTML =
        'ওজন: <b>' + gross.toFixed(3) + 'g</b> | ' + partsText(parts);
    }

    updateBarcodeLiveTotal();
  }

  function updateBarcodeLiveTotal() {
    var rows = el('bcxRows') ? qsa('.bcx-row', el('bcxRows')) : [];
    var totalGross = 0;

    rows.forEach(function (row) {
      var n = row.id.replace('bcxRow', '');
      totalGross += gramFromParts(
        toNum(el('bcxVori' + n) ? el('bcxVori' + n).value : 0),
        toNum(el('bcxAna' + n) ? el('bcxAna' + n).value : 0),
        toNum(el('bcxRoti' + n) ? el('bcxRoti' + n).value : 0),
        toNum(el('bcxPoint' + n) ? el('bcxPoint' + n).value : 0)
      );
    });

    if (!el('bcxLiveTotal')) return;

    var parts = gramToParts(totalGross);
    var p = currentBarcodePurchase;

    el('bcxLiveTotal').innerHTML =
      '<div class="bcx-line"><span>এইবার বারকোড পিস</span><b>' + rows.length + ' পিস</b></div>' +
      '<div class="bcx-line"><span>এইবার মোট ওজন</span><b>' + totalGross.toFixed(3) + 'g</b></div>' +
      '<div class="bcx-line"><span>ওজন ভাঙা</span><b>' + esc(partsText(parts)) + '</b></div>' +
      (p ? '<div class="bcx-line"><span>ক্রয়ের মোট ওজন</span><b>' + p.gross.toFixed(3) + 'g</b></div>' : '');
  }

  async function saveBarcodes() {
    var p = currentBarcodePurchase;
    if (!p) return;

    hide('bcxOk');
    hide('bcxEr');

    var rows = el('bcxRows') ? qsa('.bcx-row', el('bcxRows')) : [];
    var barcodes = [];
    var totalGross = 0;
    var hasError = false;

    rows.forEach(function (row) {
      var n = row.id.replace('bcxRow', '');

      var vori = toNum(el('bcxVori' + n) ? el('bcxVori' + n).value : 0);
      var ana = toNum(el('bcxAna' + n) ? el('bcxAna' + n).value : 0);
      var roti = toNum(el('bcxRoti' + n) ? el('bcxRoti' + n).value : 0);
      var point = toNum(el('bcxPoint' + n) ? el('bcxPoint' + n).value : 0);
      var gross = gramFromParts(vori, ana, roti, point);

      if (gross <= 0) {
        hasError = true;
        return;
      }

      totalGross += gross;

      barcodes.push({
        item_name: (el('bcxName' + n) ? el('bcxName' + n).value : '').trim() || p.item || 'আইটেম',
        karat: el('bcxKarat' + n) ? el('bcxKarat' + n).value : p.karat,
        location_id: p.location_id || 0,
        party_id: p.party_id || null,
        vori: vori,
        ana: ana,
        roti: roti,
        point: point,
        note: (el('bcxNote' + n) ? el('bcxNote' + n).value : '').trim()
      });
    });

    if (hasError) {
      show('bcxEr', 'প্রতিটা বারকোডে সঠিক ওজন দিন');
      return;
    }

    if (!barcodes.length) {
      show('bcxEr', 'কমপক্ষে ১টি বারকোড দিন');
      return;
    }

    if (p.remaining > 0 && barcodes.length > p.remaining) {
      show('bcxEr', 'বাকি পিসের বেশি বারকোড করা যাবে না');
      return;
    }

    if (p.gross > 0 && totalGross > p.gross + 0.005) {
      show('bcxEr', 'বারকোডের মোট ওজন ক্রয়ের মোট ওজনের বেশি হতে পারবে না');
      return;
    }

    var btn = el('bcxSaveBtn');
    if (btn) {
      btn.disabled = true;
      btn.textContent = 'সেভ হচ্ছে...';
    }

    try {
      var res = await fetch(API.createBarcodes + '?_t=' + Date.now(), {
        method: 'POST',
        credentials: 'same-origin',
        cache: 'no-store',
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        body: JSON.stringify({
          purchase_id: p.id,
          barcodes: barcodes
        })
      });

      var text = await res.text();
      var data;

      try {
        data = JSON.parse(text);
      } catch (e) {
        throw new Error('API JSON response দেয়নি');
      }

      if (data.success === true || data.status === true || data.ok === true) {
        show('bcxOk', '✅ বারকোড সফলভাবে তৈরি হয়েছে');

        var created = data.data && data.data.created_barcodes ? data.data.created_barcodes : [];
        if (el('bcxResult')) {
          el('bcxResult').innerHTML = created.map(function (b) {
            return '<div class="bcx-code">✅ ' + esc(b.barcode_no || '') + ' — ' + esc(b.gross_weight_gram || '') + 'g</div>';
          }).join('');
        }

        setTimeout(function () {
          closeBarcodeModal();
          loadPurchases();
        }, 1400);
      } else {
        show('bcxEr', data.message || data.error || 'বারকোড তৈরি হয়নি');
      }

    } catch (err) {
      show('bcxEr', 'সার্ভার সমস্যা: ' + err.message);
    } finally {
      if (btn) {
        btn.disabled = false;
        btn.textContent = '✅ বারকোড সেভ করুন';
      }
    }
  }

  /* =====================================================
     Events
     ===================================================== */

  function bindEvents() {
    document.addEventListener('click', function (e) {
      var target = e.target;

      if (target.id === 'addBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        openSingleModal();
        return;
      }

      if (target.id === 'cancelBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        closeSingleModal();
        return;
      }

      if (target.id === 'mBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        saveSinglePurchase();
        return;
      }

      if (target.id === 'multiBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        openMultiModal();
        return;
      }

      if (target.id === 'addRowBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        addMultiRow();
        return;
      }

      if (target.id === 'multiCancelBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        closeMultiModal();
        return;
      }

      if (target.id === 'multiSaveBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        saveMultiEntries();
        return;
      }

      if (target.dataset && target.dataset.multiDel) {
        e.preventDefault();
        e.stopImmediatePropagation();
        removeMultiRow(target.dataset.multiDel);
        return;
      }

      if (target.id === 'searchBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        loadPurchases();
        return;
      }

      var singleItem = target.closest ? target.closest('.party-suggest-item[data-single-party-id]') : null;
      if (singleItem) {
        e.preventDefault();
        e.stopImmediatePropagation();
        selectSingleParty(singleItem.getAttribute('data-single-party-id'));
        return;
      }

      var bcBtn = target.closest ? target.closest('[data-bc-open]') : null;
      if (bcBtn) {
        e.preventDefault();
        e.stopImmediatePropagation();
        openBarcodeModal(bcBtn.getAttribute('data-bc-open'));
        return;
      }

      if (target.id === 'bcxAddRowBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        addBarcodeRow();
        return;
      }

      if (target.id === 'bcxCancelBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        closeBarcodeModal();
        return;
      }

      if (target.id === 'bcxSaveBtn') {
        e.preventDefault();
        e.stopImmediatePropagation();
        saveBarcodes();
        return;
      }

      if (target.dataset && target.dataset.bcxDel) {
        e.preventDefault();
        e.stopImmediatePropagation();
        removeBarcodeRow(target.dataset.bcxDel);
        return;
      }

      if (target.id === 'purModal' && target === e.currentTarget) {
        closeSingleModal();
      }

      if (target.id === 'multiModal' && target === e.currentTarget) {
        closeMultiModal();
      }

      if (target.id === 'manualBcModal' && target === e.currentTarget) {
        closeBarcodeModal();
      }
    }, true);

    document.addEventListener('input', function (e) {
      var ids = ['wVori', 'wAna', 'wRoti', 'wPoint', 'mRate', 'mPieces'];
      if (ids.indexOf(e.target.id) >= 0) calcSingle();

      if (e.target.dataset && e.target.dataset.multiCalc) {
        calcMultiRow(e.target.dataset.multiCalc);
      }

      if (e.target.id === 'mRate2') {
        qsa('.entry-row', el('multiRows')).forEach(function (row) {
          calcMultiRow(row.id.replace('mr-', ''));
        });
      }

      if (e.target.dataset && e.target.dataset.bcxCalc) {
        updateBarcodeRow(e.target.dataset.bcxCalc);
      }
    });

    document.addEventListener('change', function (e) {
      if (e.target.id === 'mKarat') calcSingle();

      if (e.target.dataset && e.target.dataset.multiCalc) {
        calcMultiRow(e.target.dataset.multiCalc);
      }

      if (e.target.id && e.target.id.indexOf('bcxKarat') === 0) {
        updateBarcodeLiveTotal();
      }
    });

    document.addEventListener('click', function (e) {
      var singleBox = el('mPartySuggest');
      var singleSearch = el('mPartySearch');

      if (singleBox && singleSearch) {
        if (e.target !== singleSearch && !singleBox.contains(e.target)) {
          hideSinglePartySuggestions();
        }
      }

      qsa('.multi-party-suggest').forEach(function (box) {
        var parent = box.parentNode;
        if (!parent) return;

        var input = parent.querySelector('.multi-party-search');
        if (!input) return;

        if (e.target !== input && !box.contains(e.target)) {
          box.style.display = 'none';
        }
      });
    });
  }

  function patchOldInlineFunctions() {
    window.openMultiModal = openMultiModal;
    window.closeMultiModal = closeMultiModal;
    window.addMultiRow = addMultiRow;
    window.removeRow = removeMultiRow;
    window.saveMultiEntries = saveMultiEntries;
    window.calcRow = calcMultiRow;
    window.calcMultiTotal = calcMultiTotal;
  }

  function init() {
    injectStyle();

    if (el('mDate') && !el('mDate').value) el('mDate').value = today;
    if (el('fromDate') && !el('fromDate').value) el('fromDate').value = today;
    if (el('toDate') && !el('toDate').value) el('toDate').value = today;

    bindEvents();
    patchOldInlineFunctions();

    loadParties();
    loadAccounts();
    calcSingle();
    loadPurchases();

    setInterval(function () {
      patchOldInlineFunctions();
      enhanceAllMultiPartySelects();
    }, 1000);
  }

  window.calcPurchase = calcSingle;
  window.openPurchaseModal = openSingleModal;
  window.closePurchaseModal = closeSingleModal;
  window.lpur = loadPurchases;
  window.purchaseEnhanceMultiPartySelects = enhanceAllMultiPartySelects;

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }

})();