Actualmente estoy trabajando en crear un programa con electron vite ract y mariadb


y uso esta dependencia para afip "@afipsdk/afip.js": "^1.1.3"
todas.
{
  "name": "inventory",
  "private": true,
  "version": "1.0.0",
  "description": "Sistema de gestión para restaurantes",
  "main": "src/electron/main.js",
  "author": "Brezlo",
  "scripts": {
    "dev": "concurrently -k \"vite\" \"wait-on tcp:5173 && electron .\"",
    "build": "vite build",
    "start": "electron .",
    "lint": "eslint .",
    "preview": "vite preview",
    "dist": "npm run build && electron-builder",
    "postinstall": "electron-builder install-app-deps"
  },
  "build": {
    "appId": "com.brezlo.inventorysystem",
    "productName": "Inventory",
    "copyright": "Copyright © 2025",
    "electronVersion": "28.1.0",
    "directories": {
      "buildResources": "assets",
      "output": "dist"
    },
    "files": [
      "dist/**/*",
      "src/electron/**/*",
      "src/utils/ticketUtils.cjs",
      "src/pages/Ticket/components/defaultTicketTemplates.cjs",
      "package.json"
    ],
    "win": {
      "target": "nsis",
      "icon": "assets/icon.ico"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true,
      "perMachine": true,
      "deleteAppDataOnUninstall": true,
      "uninstallerFlags": [
        "--confirm-deletion"
      ]
    },
    "extraResources": []
  },
  "dependencies": {
    "@afipsdk/afip.js": "^1.1.3",
    "@emotion/react": "^11.14.0",
    "@emotion/styled": "^11.14.0",
    "@hello-pangea/dnd": "^18.0.1",
    "@mui/icons-material": "^7.1.0",
    "@mui/material": "^7.1.0",
    "bcrypt": "^6.0.0",
    "concurrently": "^9.1.2",
    "docx": "^9.5.0",
    "electron-updater": "^6.1.7",
    "exceljs": "^4.4.0",
    "fast-xml-parser": "^5.2.3",
    "focus-trap-react": "^11.0.4",
    "lodash.get": "^4.4.2",
    "mysql2": "^3.14.1",
    "papaparse": "^5.5.3",
    "qrcode.react": "^4.2.0",
    "react": "^19.1.0",
    "react-dom": "^19.1.0",
    "react-router-dom": "^7.6.0",
    "react-to-print": "^3.1.0",
    "soap": "^1.1.12",
    "wait-on": "^8.0.3"
  },
  "devDependencies": {
    "@eslint/js": "^9.25.0",
    "@types/react": "^19.1.2",
    "@types/react-dom": "^19.1.2",
    "@vitejs/plugin-react": "^4.4.1",
    "electron": "^28.1.0",
    "electron-builder": "^24.9.1",
    "electron-rebuild": "^3.2.9",
    "eslint": "^9.25.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.19",
    "globals": "^16.0.0",
    "vite": "^6.3.5"
  }
}


Es para negocio de comida o de cualquier otro mientras maneje stock.
Hay varios roles:
El Noble: admin que carga productos, variantes, insumos, extras, productos aditivos.etc
El Capitalista: cajero que vende productos y debe elegir productos aditivos como masa sin TACC, 
extras como más queso, etc. 
El indigente que es el mozo.

Los productos o articulos tienen:
Insumos (ej: harina, queso, tomate.etc)
Producto aditivo(ej: masa celiaca, guarnicion ensalada, guarnicion papas) 
(con sus insumos que tambien estan en el mismo modal)
- Extras (que se agregan ej: mas tomate, mas papas

Tengo una parte en la que elijo que insumos agregar a un producto por ejemplo y tengo un dropdown q aparecen ahi los insumos q ya se crearon ...
Por ejemplo creo el insumo Harina, y luego creo el producto Masa y en masa luego me da la opcion de seleccionar el insumo.
Todo funciona perfecto, pero tengo un problema q a la larga afectara todo, cuantos mas insumos cree, mas largo sera el dropdown por ejemplo para seleccionar quedaria algo asi

Por ejemplo tengo esta parte que dice:
Insumos de la Receta
Añadir Insumo a la Receta: Seleccionar insumo >
Insumo 1
Insumo 2
Insumo 3
Insumo 4
Insumo 5
Insumo 6
Insumo 7
Insumo 8
y asi seguiria con los demas insumos cada vez mas. y esto afectaria mas adelante.
Lo mejor seria reemplazar esa parte por un buscador, pero sin afectar nada mas solo cambiarlo por search q al poner por ejemplo la "H aparazcan todos los insumos q comienzan por H" y asi...o sea un buen buscador y luego lo selecciones y se agregue como lo hace ahora.

Estos son los archivos 
// src/pages/ProductOptions/ModalDefinirReceta.jsx

import React from 'react';
import CloseIcon from '@mui/icons-material/Close';
import FocusTrap from 'focus-trap-react';
import './ModalDefinirReceta.css';

// Importamos los componentes de UI
import ProductDetails from './components/ProductDetails';
import PricingSection from './components/PricingSection';
import RecipeItemsList from './components/RecipeItemsList';
import ProductOptions from './components/ProductOptions';
import { useProductRecipeForm } from './hooks/useProductRecipeForm';

const ModalDefinirReceta = ({ productoId, onClose }) => {
  const form = useProductRecipeForm(productoId, onClose);
  
  if (form.loading && !form.productoOriginal) {
    return (
        <div className="modal___overlay">
            <div className="modal-definir-receta__container" style={{ padding: "2rem", textAlign: "center" }}>
                <p>Cargando datos...</p>
            </div>
        </div>
    );
  }

  if (form.error && !form.productoOriginal && !form.loading) {
    return (
        <div className="modal___overlay">
            <div className="modal-definir-receta__container" style={{ padding: "2rem" }}>
                <div className="modal-definir-receta__header">
                    <h2>Error al Cargar</h2>
                    <button onClick={onClose} className="modal_close_btn"><CloseIcon /></button>
                </div>
                <p className="modal-definir-receta__error-global">{form.error}</p>
                <div style={{ textAlign: 'right' }}>
                    <button type="button" className="footer-btn-cancelar" onClick={onClose}>Cerrar</button>
                </div>
            </div>
        </div>
    );
  }

return (
  <div className="modal___overlay">
    <FocusTrap>
    <div className="modal-definir-receta__container">

      {(form.loading || form.guardando) && (
          <div className="modal-definir-receta__activity-overlay">
              <p>{form.guardando ? 'Guardando...' : 'Cargando...'}</p>
          </div>
      )}

      <div className="modal-definir-receta__header">
        <h2>{form.productoOriginal ? `Editando: ${form.productoOriginal.nombre}` : 'Definiendo Receta'}</h2>
        <button onClick={onClose} className="modal_close_btn" disabled={form.guardando}><CloseIcon /></button>
      </div>

      {form.error && <p className="modal-definir-receta__error-global">{form.error}</p>}

      <div className="modal-definir-receta__content">
          <ProductDetails
              nombreProductoEdit={form.nombreProductoEdit}
              setNombreProductoEdit={form.setNombreProductoEdit}
              tipoCantidad={form.tipoCantidad}
              setTipoCantidad={form.setTipoCantidad}
              categorias={form.categorias}
              categoriaSeleccionadaId={form.categoriaSeleccionadaId}
              setCategoriaSeleccionadaId={form.setCategoriaSeleccionadaId}
              disabled={form.isDisabled}
          />

          <PricingSection
              precioBrutoStr={form.precioBrutoStr}
              handlePrecioBrutoInputChange={form.handlePrecioBrutoInputChange}
              precioTotalStr={form.precioTotalStr}
              handlePrecioTotalInputChange={form.handlePrecioTotalInputChange}
              tasaIvaIdSeleccionada={form.tasaIvaIdSeleccionada}
              handleTasaIVAChange={form.handleTasaIVAChange}
              montoIvaDisplay={form.montoIvaDisplay}
              listaTasasIVA={form.listaTasasIVA}
              handleAddNuevaTasa={form.handleAddNuevaTasa}
              disabled={form.isDisabled}
              guardando={form.guardando}
          />

          <hr className="section-divider" />
          <RecipeItemsList
              recetaItems={form.recetaItems}
              todosLosInsumos={form.todosLosInsumos}
              agregarInsumo={form.agregarInsumo}
              actualizarItemReceta={form.actualizarItemReceta}
              quitarInsumo={form.quitarInsumo}
              calcularCostoParcialItem={form.calcularCostoParcialItem}
              disabled={form.isDisabled}
          />

          <hr className="section-divider" />        
          <ProductOptions 
              aditivosGlobales={form.aditivosGlobales}
              aditivosAsignados={form.aditivosAsignados}
              setAditivosAsignados={form.setAditivosAsignados}
              configuracionesAditivos={form.configuracionesAditivos}
              handleAditivoConfigChange={form.handleAditivoConfigChange}
              modificadoresGlobales={form.modificadoresGlobales}
              modificadoresAsignados={form.modificadoresAsignados}
              handleToggleModificador={form.handleToggleModificador}
              todosLosInsumos={form.todosLosInsumos}
              disabled={form.isDisabled}
          />
      </div>

      <div className="modal-definir-receta__footer">
        <div className="footer-costo">
            <h3>Costo Total Estimado: ${form.costoTotalEstimado.toFixed(2)}</h3>
        </div>
        <div className="footer-acciones">
            <button type="button" className="footer-btn-cancelar" onClick={onClose} disabled={form.guardando}>Cancelar</button>
            <button type="button" className="footer-btn-guardar" onClick={form.handleGuardarTodo} disabled={form.isSaveButtonDisabled}>
                {form.guardando ? 'Guardando...' : 'Guardar Receta'}
            </button>
        </div>
      </div>

    </div>
    </FocusTrap>
  </div>
);
}

export default ModalDefinirReceta;

import React from 'react';
import Tooltip from '@mui/material/Tooltip';

const RecipeItemsList = ({
  recetaItems, todosLosInsumos,
  agregarInsumo, actualizarItemReceta, quitarInsumo,
  calcularCostoParcialItem,
  disabled
}) => {
  return (
    <>
      <h3 className="section-title">Insumos de la Receta</h3>
      <div className="modal-definir-receta__add-insumo-section">
        <label htmlFor="insumo-selector">Añadir Insumo a la Receta:</label>
        <select id="insumo-selector" disabled={disabled || !Array.isArray(todosLosInsumos) || !todosLosInsumos.length} onChange={(e) => { if (e.target.value) agregarInsumo(e.target.value); e.target.value = ""; }} value="">
          <option value="" disabled>-- Seleccionar Insumo --</option>
          {Array.isArray(todosLosInsumos) && todosLosInsumos.filter(insumo => !recetaItems.some(item => item.insumoOriginal.id === insumo.id)).map(insumo => (<option key={insumo.id} value={insumo.id}> {insumo.nombre} (Stock: {insumo.cantidad_stock} {insumo.unidad_stock}) </option>))}
        </select>
      </div>
      <div className="modal-definir-receta__items-list">
        {recetaItems.length === 0 ? (<p className="modal-definir-receta__no-items">Añade insumos para definir la receta.</p>) : (
          recetaItems.map(item => {
            const insumoOriginal = item.insumoOriginal;
            if (!insumoOriginal) return null;
            const costoParcialUI = calcularCostoParcialItem(item);
            return (
              <div key={item.insumo_id} className="modal-definir-receta__item">
                <span className="item-nombre" title={`ID: ${insumoOriginal.id} | Stock: ${insumoOriginal.cantidad_stock} ${insumoOriginal.unidad_stock} @ $${parseFloat(insumoOriginal.precio_por_unidad_stock).toFixed(2)}/${insumoOriginal.unidad_stock}`}>
                  {insumoOriginal.nombre} <small>({insumoOriginal.unidad_stock})</small>
                </span>
                <input type="text" inputMode="decimal" className="item-cantidad" placeholder="Cant." value={item.cantidadUsada} onChange={e => { const val = e.target.value; if (val === "" || /^[0-9]*\.?[0-9]*$/.test(val)) { actualizarItemReceta(item.insumo_id, 'cantidadUsada', val); } }} disabled={disabled} aria-label={`Cantidad de ${insumoOriginal.nombre}`} />
                <input type="text" className="item-unidad" placeholder={`Unidad (ej: ${insumoOriginal.unidad_stock})`} value={item.unidad_usada_en_receta || ''} onChange={e => { actualizarItemReceta(item.insumo_id, 'unidad_usada_en_receta', e.target.value); }} disabled={disabled} aria-label={`Unidad de ${insumoOriginal.nombre}`} />
                <span className="item-costo">Costo: {isNaN(costoParcialUI) ? <Tooltip title={`Unidad receta '${item.unidad_usada_en_receta}' no coincide con unidad stock '${insumoOriginal.unidad_stock}' o cantidad inválida.`}><strong style={{ color: 'orange', cursor: 'help' }}>No Calc.</strong></Tooltip> : `$${costoParcialUI.toFixed(2)}`}</span>
                <button type="button" className="item-quitar" onClick={() => quitarInsumo(item.insumo_id)} disabled={disabled}>×</button>
              </div>
            );
          })
        )}
      </div>
    </>
  );
};

export default RecipeItemsList;
// electron/db/database.js
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
const {
  defaultTemplateFacturaB,
  defaultTemplateFacturaA,
  defaultTemplateComandaCocina,
} = require('../../pages/Ticket/components/defaultTicketTemplates.cjs');

function safeDecimalCalculation(num1, num2, operation, precision = 3) {
  const internalPrecision = Math.max(5, precision);
  const factor = Math.pow(10, internalPrecision);
  
  const int1 = Math.round(parseFloat(num1) * factor);
  
  let resultInt;

  if (operation === 'multiply') {
    resultInt = Math.round(int1 * parseFloat(num2));
  } else {
    const int2 = Math.round(parseFloat(num2) * factor);
    if (operation === 'subtract') {
      resultInt = int1 - int2;
    } else {
      resultInt = int1 + int2;
    }
  }
  
  const finalFactor = Math.pow(10, precision);
  return Math.round(resultInt / (factor / finalFactor)) / finalFactor;
}
let pool;



const plantillasPorDefecto = [
  { name: 'facturaB', structure: defaultTemplateFacturaB },
  { name: 'facturaA', structure: defaultTemplateFacturaA },
  { name: 'comandaCocina', structure: defaultTemplateComandaCocina },
];

async function initializeDatabase(dbConfig) {
  if (pool) return pool;
  if (!dbConfig) {
    throw new Error("La configuración de la base de datos es requerida para la inicialización.");
  }
  
  try {
    pool = mysql.createPool({
      host: dbConfig.host,
      port: dbConfig.port || 3306,
      user: dbConfig.user,
      password: dbConfig.password,
      database: dbConfig.database,
      waitForConnections: true,
      connectionLimit: 15,
      queueLimit: 0,
      connectTimeout: 20000,
      authPlugins: {
        mysql_native_password: () => Buffer.from([0])
      }
    });

    // Probar la conexión con las credenciales de la app
    const connection = await pool.getConnection();
    console.log(`[DB:initializeDatabase] Conectado a MariaDB en ${dbConfig.host} usando las credenciales de la app.`);
    connection.release();

    // Aquí se intenta crear las tablas e insertar datos por defecto
    await createTables(); 
    await insertDefaultTasas();
    await insertDefaultTemplates();

    console.log('[DB:initializeDatabase] Base de datos inicializada con éxito (tablas verificadas/creadas, datos por defecto insertados).');
    return pool;

  } catch (error) {
    console.error('[DB:initializeDatabase] ERROR al inicializar la conexión con MariaDB o al crear tablas/datos por defecto:', error);
    if (error.code === 'ECONNREFUSED') {
        console.error(`[DB:initializeDatabase] Error de conexión: No se pudo conectar a MariaDB en ${dbConfig.host}:${dbConfig.port}. Verifica que el servidor esté corriendo y accesible y que las credenciales en config.json sean correctas.`);
    } else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
        console.error(`[DB:initializeDatabase] Error de acceso: Usuario o contraseña incorrectos para MariaDB usando las credenciales de la app. Revisa tu config.json.`);
    } else if (error.code === 'ER_BAD_DB_ERROR') {
        console.error(`[DB:initializeDatabase] Error de base de datos: La base de datos '${dbConfig.database}' no existe en el servidor MariaDB o el usuario de la app no tiene permisos sobre ella. Revisa tu config.json o el proceso de setup.`);
    } else {
         console.error(`[DB:initializeDatabase] Otro error de DB:`, error.message, `(Código: ${error.code})`);
    }
    throw error; 
  }
}

async function createTables() {
  const connection = await pool.getConnection();
  let currentQuery = ''; // Variable para guardar una referencia a la query que está en ejecución
  try { // <-- ESTEasdasdasdas
    console.log("[DB:createTables] Iniciando creación/verificación de tablas...");

    currentQuery = 'CREATE TABLE IF NOT EXISTS clientes ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS clientes (
          id INT AUTO_INCREMENT PRIMARY KEY,
          nombre VARCHAR(255) NOT NULL,
          cuit VARCHAR(11) NOT NULL UNIQUE,
          condicionIVA ENUM('Responsable Inscripto', 'Monotributista', 'Consumidor Final') NOT NULL,
          domicilio VARCHAR(255),
          telefono VARCHAR(20),
          email VARCHAR(255),
          created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'clientes' verificada/creada.");
    } catch (e) { 
      console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); 
      throw e; 
    }
    currentQuery = 'CREATE TABLE IF NOT EXISTS tasas_iva ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS tasas_iva (
          id INT AUTO_INCREMENT PRIMARY KEY,
          nombre_tasa VARCHAR(255),
          valor_tasa DOUBLE NOT NULL UNIQUE,
          descripcion TEXT
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'tasas_iva' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; } // Re-lanza

    currentQuery = 'CREATE TABLE IF NOT EXISTS insumos ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS insumos (
          id INT AUTO_INCREMENT PRIMARY KEY,
          nombre VARCHAR(255) NOT NULL UNIQUE,
          cantidad_stock DECIMAL(10, 3) NOT NULL DEFAULT 0.000,
          unidad_stock VARCHAR(50) NOT NULL,
          precio_por_unidad_stock DECIMAL(10, 2) NOT NULL DEFAULT 0.00
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'insumos' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS productos ...';
    try {
        await connection.query(`
          CREATE TABLE IF NOT EXISTS productos (
            id INT AUTO_INCREMENT PRIMARY KEY,
            nombre VARCHAR(255) NOT NULL UNIQUE,
            precio_venta DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
            tipo_cantidad ENUM('entero', 'decimal') NOT NULL DEFAULT 'entero',
            imprimir_en_cocina BOOLEAN NOT NULL DEFAULT TRUE,
            tasa_iva_id INT,
            FOREIGN KEY(tasa_iva_id) REFERENCES tasas_iva(id) ON DELETE SET NULL
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
        `);
        console.log("[DB:createTables] Tabla 'productos' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS categorias ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS categorias (
          id INT AUTO_INCREMENT PRIMARY KEY,
          nombre VARCHAR(100) NOT NULL UNIQUE,
          descripcion TEXT,
          orden INT DEFAULT 0
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'categorias' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS producto_modificadores ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS producto_modificadores (
          id INT AUTO_INCREMENT PRIMARY KEY,
          nombre VARCHAR(100) NOT NULL UNIQUE,
          precio_adicional DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
          insumo_id INT NULL,
          cantidad_insumo DECIMAL(10, 3) NULL,
          markup_porcentaje DECIMAL(7, 2) NULL DEFAULT 100.00,
          disponible BOOLEAN NOT NULL DEFAULT TRUE,
          FOREIGN KEY (insumo_id) REFERENCES insumos(id) ON DELETE SET NULL
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'producto_modificadores' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS producto_modificadores_disponibles ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS producto_modificadores_disponibles (
          producto_id INT NOT NULL,
          modificador_id INT NOT NULL,
          PRIMARY KEY (producto_id, modificador_id),
          FOREIGN KEY (producto_id) REFERENCES productos(id) ON DELETE CASCADE,
          FOREIGN KEY (modificador_id) REFERENCES producto_modificadores(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'producto_modificadores_disponibles' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    // Alteraciones de tablas: Usamos un try/catch por alteración para logs más claros
    currentQuery = 'ALTER TABLE productos ADD COLUMN categoria_id ...';
    try {
      console.log("[DB:createTables] Intentando añadir categoria_id a productos...");
      await connection.query("ALTER TABLE productos ADD COLUMN categoria_id INT NULL AFTER tasa_iva_id;");
      await connection.query("ALTER TABLE productos ADD CONSTRAINT fk_producto_categoria FOREIGN KEY (categoria_id) REFERENCES categorias(id) ON DELETE SET NULL;");
      console.log("[DB:createTables] categoria_id añadido a productos (o ya existía).");
    } catch (e) {
      // Solo re-lanzar si NO es un error de campo/FK duplicado (ER_DUP_FIELDNAME, ER_FK_DUP_NAME)
      if (e.code !== 'ER_DUP_FIELDNAME' && e.code !== 'ER_FK_DUP_NAME') { 
         console.error(`[DB:createTables] ERROR NO DUPLICADO/FK en ${currentQuery}:`, e); 
         throw e; // Si no es un error de duplicado, lanza el error.
      } else {
          console.warn(`[DB:createTables] Advertencia en ${currentQuery} (campo ya existe):`, e.message);
      }
    }

    currentQuery = 'ALTER TABLE productos ADD COLUMN producto_padre_id ...';
    try {
        console.log("[DB:createTables] Intentando añadir producto_padre_id a productos...");
        await connection.query("ALTER TABLE productos ADD COLUMN producto_padre_id INT NULL AFTER categoria_id;");
        await connection.query("ALTER TABLE productos ADD CONSTRAINT fk_producto_padre FOREIGN KEY (producto_padre_id) REFERENCES productos(id) ON DELETE CASCADE;");
        console.log("[DB:createTables] producto_padre_id añadido a productos (o ya existía).");
    } catch (e) {
        if (e.code !== 'ER_DUP_FIELDNAME' && e.code !== 'ER_FK_DUP_NAME') {
            console.error(`[DB:createTables] ERROR NO DUPLICADO/FK en ${currentQuery}:`, e);
            throw e;
        } else {
             console.warn(`[DB:createTables] Advertencia en ${currentQuery} (campo ya existe):`, e.message);
        }
    }

    currentQuery = 'ALTER TABLE productos ADD COLUMN disponible_para_venta ...';
    try {
      console.log("[DB:createTables] Intentando añadir disponible_para_venta a productos...");
      await connection.query("ALTER TABLE productos ADD COLUMN disponible_para_venta BOOLEAN NOT NULL DEFAULT TRUE AFTER tipo_cantidad;");
      console.log("[DB:createTables] disponible_para_venta añadido a productos (o ya existía).");
    } catch(e) {
      if (e.code !== 'ER_DUP_FIELDNAME') {
        console.error(`[DB:createTables] ERROR NO DUPLICADO en ${currentQuery}:`, e);
        throw e;
      } else {
        console.warn(`[DB:createTables] Advertencia en ${currentQuery} (campo ya existe):`, e.message);
      }
    }

    // --- NUEVAS TABLAS PARA ADITIVOS ---
    currentQuery = 'CREATE TABLE IF NOT EXISTS aditivo_grupos ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS aditivo_grupos (
          id INT(11) NOT NULL AUTO_INCREMENT,
          nombre VARCHAR(255) NOT NULL,
          es_obligatorio TINYINT(1) NOT NULL DEFAULT 0,
          PRIMARY KEY (id),
          UNIQUE KEY nombre (nombre)
        ) ENGINE=InnoDB;
      `);
      console.log("[DB:createTables] Tabla 'aditivo_grupos' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS aditivo_opciones ...';
    try {
        await connection.query(`
          CREATE TABLE IF NOT EXISTS aditivo_opciones (
            id INT(11) NOT NULL AUTO_INCREMENT,
            grupo_id INT(11) NOT NULL,
            nombre VARCHAR(255) NOT NULL,
            PRIMARY KEY (id),
            UNIQUE KEY grupo_id_nombre (grupo_id, nombre),
            CONSTRAINT fk_opcion_a_grupo FOREIGN KEY (grupo_id) REFERENCES aditivo_grupos (id) ON DELETE CASCADE
          ) ENGINE=InnoDB;
        `);
        console.log("[DB:createTables] Tabla 'aditivo_opciones' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS aditivo_opciones_recetas ...';
    try {
      await connection.query(`
      CREATE TABLE IF NOT EXISTS aditivo_opciones_recetas (
        id INT(11) NOT NULL AUTO_INCREMENT,
        opcion_id INT(11) NOT NULL,
        insumo_id INT(11) NOT NULL,
        cantidad DECIMAL(10,3) NOT NULL,
        PRIMARY KEY (id),
        UNIQUE KEY opcion_id_insumo_id (opcion_id,insumo_id),
        CONSTRAINT fk_receta_a_opcion FOREIGN KEY (opcion_id) REFERENCES aditivo_opciones (id) ON DELETE CASCADE,
        CONSTRAINT fk_receta_a_insumo FOREIGN KEY (insumo_id) REFERENCES insumos (id) ON DELETE CASCADE
      ) ENGINE=InnoDB;
    `);
      console.log("[DB:createTables] Tabla 'aditivo_opciones_recetas' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS producto_aditivos ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS producto_aditivos (
          id INT(11) NOT NULL AUTO_INCREMENT,
          producto_id INT(11) NOT NULL,
          opcion_id INT(11) NOT NULL,
          precio_adicional DECIMAL(10,2) NOT NULL DEFAULT 0.00,
          PRIMARY KEY (id),
          UNIQUE KEY producto_opcion_unique (producto_id, opcion_id),
          CONSTRAINT fk_prod_aditivo_a_producto FOREIGN KEY (producto_id) REFERENCES productos (id) ON DELETE CASCADE,
          CONSTRAINT fk_prod_aditivo_a_opcion FOREIGN KEY (opcion_id) REFERENCES aditivo_opciones (id) ON DELETE CASCADE
        ) ENGINE=InnoDB;
      `);
      console.log("[DB:createTables] Tabla 'producto_aditivos' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS producto_receta_detalle ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS producto_receta_detalle (
          id INT AUTO_INCREMENT PRIMARY KEY,
          producto_id INT NOT NULL,
          insumo_id INT NOT NULL,
          cantidad_usada_en_receta DECIMAL(10, 3) NOT NULL,
          unidad_usada_en_receta VARCHAR(50) NOT NULL,
          FOREIGN KEY(producto_id) REFERENCES productos(id) ON DELETE CASCADE,
          FOREIGN KEY(insumo_id) REFERENCES insumos(id) ON DELETE RESTRICT,
          UNIQUE(producto_id, insumo_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'producto_receta_detalle' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS usuarios ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS usuarios (
          id INT AUTO_INCREMENT PRIMARY KEY,
          username VARCHAR(255) UNIQUE NOT NULL,
          password VARCHAR(255) NOT NULL,
          role VARCHAR(50) NOT NULL CHECK(role IN ('Noble', 'Capitalista', 'Indigente'))
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'usuarios' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS ventas ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS ventas (
          id INT AUTO_INCREMENT PRIMARY KEY,
          fecha_hora DATETIME DEFAULT CURRENT_TIMESTAMP,
          total_venta DECIMAL(10, 2) NOT NULL,
          -- AÑADIR ESTAS 3 COLUMNAS:
          neto_gravado DECIMAL(10, 2) NULL,
          monto_iva DECIMAL(10, 2) NULL,
          descuento DECIMAL(10, 2) NULL,
          -- FIN AÑADIR
          usuario_id INT,
          metodo_pago VARCHAR(50),
          estado VARCHAR(20) NOT NULL DEFAULT 'COMPLETADA',
          monto_pagado_cliente DECIMAL(10, 2) DEFAULT NULL,
          vuelto_entregado DECIMAL(10, 2) DEFAULT NULL,
          notas TEXT NULL,
          cae VARCHAR(14) NULL,
          cae_vto DATE NULL,
          punto_venta_afip VARCHAR(4) NULL,
          afip_bill_number VARCHAR(8) NULL,
          tipo_comprobante_afip INT NULL,
          afip_qr_data TEXT NULL,
          cliente_id INT NULL,
          cliente_nombre VARCHAR(255) NULL,
          cliente_cuit VARCHAR(11) NULL,
          cliente_condicion_iva VARCHAR(50) NULL,
          cliente_domicilio VARCHAR(255) NULL,
          FOREIGN KEY(usuario_id) REFERENCES usuarios(id) ON DELETE SET NULL,
          FOREIGN KEY(cliente_id) REFERENCES clientes(id) ON DELETE SET NULL
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'ventas' verificada/creada con columnas de cliente y AFIP.");

      const alterVentas = [
        "ADD COLUMN neto_gravado DECIMAL(10, 2) NULL",
        "ADD COLUMN monto_iva DECIMAL(10, 2) NULL",
        "ADD COLUMN descuento DECIMAL(10, 2) NULL"
      ];
      for (const alterQuery of alterVentas) {
        try {
            await connection.query(`ALTER TABLE ventas ${alterQuery};`);
            console.log(`[DB:createTables] Alteración en 'ventas' ejecutada: ${alterQuery}`);
        } catch(e) {
            if (e.code === 'ER_DUP_FIELDNAME') {
                console.warn(`[DB:createTables] Advertencia: Columna ya existe en 'ventas': ${alterQuery}`);
            } else {
                console.error(`[DB:createTables] Error al alterar 'ventas' con "${alterQuery}":`, e);
            }
        }
      }
    } catch (e) {
      console.error(`[DB:createTables] ERROR al crear/modificar tabla 'ventas':`, e);
      throw e;
    }

    currentQuery = 'CREATE TABLE IF NOT EXISTS venta_detalle ...';
    try {
      await connection.query(`
      CREATE TABLE IF NOT EXISTS venta_detalle (
        id INT AUTO_INCREMENT PRIMARY KEY,
        venta_id INT NOT NULL,
        producto_id INT NULL,
        descripcion_venta VARCHAR(512) NOT NULL,
        cantidad DECIMAL(10, 3) NOT NULL,
        precio_unitario_venta DECIMAL(10, 2) NOT NULL,
        tasa_iva_id INT NULL,
        costo_unitario_produccion DECIMAL(10, 2) NULL,
        subtotal DECIMAL(10, 2) NOT NULL,
        FOREIGN KEY(venta_id) REFERENCES ventas(id) ON DELETE CASCADE,
        FOREIGN KEY(producto_id) REFERENCES productos(id) ON DELETE SET NULL,
        FOREIGN KEY(tasa_iva_id) REFERENCES tasas_iva(id) ON DELETE SET NULL
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'venta_detalle' verificada/creada/actualizada.");
      
      const alterVentaDetalle = [
        "ADD COLUMN tasa_iva_id INT NULL",
        "ADD CONSTRAINT fk_venta_detalle_tasa_iva FOREIGN KEY (tasa_iva_id) REFERENCES tasas_iva(id) ON DELETE SET NULL",
    ];
     for (const alterQuery of alterVentaDetalle) {
          try {
              await connection.query(`ALTER TABLE venta_detalle ${alterQuery};`);
              console.log(`[DB:createTables] Alteración en 'venta_detalle' ejecutada: ${alterQuery}`);
          } catch(e) {
               if (e.code === 'ER_DUP_FIELDNAME' || e.code === 'ER_FK_DUP_NAME') {
                   console.warn(`[DB:createTables] Advertencia: Columna/FK ya existe en 'venta_detalle': ${alterQuery}`);
               } else {
                   console.error(`[DB:createTables] Error al alterar 'venta_detalle' con "${alterQuery}":`, e);
               }
          }
     }
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }


    currentQuery = 'CREATE TABLE IF NOT EXISTS venta_pagos_desglose ...';
    try {
        await connection.query(`
        CREATE TABLE IF NOT EXISTS venta_pagos_desglose (
          id INT AUTO_INCREMENT PRIMARY KEY,
          venta_id INT NOT NULL,
          moneda VARCHAR(3) NOT NULL,
          denominacion DECIMAL(10, 2) NOT NULL,
          cantidad INT NOT NULL,
          FOREIGN KEY (venta_id) REFERENCES ventas(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'venta_pagos_desglose' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS movimientos_stock ...';
    try {
        await connection.query(`
        CREATE TABLE IF NOT EXISTS movimientos_stock (
          id INT AUTO_INCREMENT PRIMARY KEY,
          insumo_id INT NOT NULL,
          cantidad_movida DECIMAL(10, 3) NOT NULL,
          tipo_movimiento VARCHAR(50) NOT NULL CHECK(tipo_movimiento IN ('venta', 'compra', 'ajuste_manual', 'merma', 'anulacion_venta')),
          fecha_hora DATETIME DEFAULT CURRENT_TIMESTAMP,
          referencia_id INT,
          notas TEXT,
          FOREIGN KEY(insumo_id) REFERENCES insumos(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
        `);
        console.log("[DB:createTables] Tabla 'movimientos_stock' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS proveedores ...';
    try {
        await connection.query(`
          CREATE TABLE IF NOT EXISTS proveedores (
            id INT AUTO_INCREMENT PRIMARY KEY,
            nombre VARCHAR(255) NOT NULL UNIQUE,
            cuit VARCHAR(20) UNIQUE,
            telefono VARCHAR(50),
            email VARCHAR(255),
            direccion TEXT,
            notas TEXT
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
        `);
        console.log("[DB:createTables] Tabla 'proveedores' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS compras_proveedores ...';
    try {
        await connection.query(`
          CREATE TABLE IF NOT EXISTS compras_proveedores (
            id INT AUTO_INCREMENT PRIMARY KEY,
            proveedor_id INT NOT NULL,
            fecha_factura DATE NOT NULL,
            numero_factura VARCHAR(100),
            total_compra DECIMAL(10, 2),
            notas TEXT,
            fecha_registro DATETIME DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY(proveedor_id) REFERENCES proveedores(id) ON DELETE RESTRICT
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
        `);
        console.log("[DB:createTables] Tabla 'compras_proveedores' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS compras_proveedores_detalle ...';
    try {
        await connection.query(`
          CREATE TABLE IF NOT EXISTS compras_proveedores_detalle (
            id INT AUTO_INCREMENT PRIMARY KEY,
            compra_id INT NOT NULL,
            insumo_id INT NOT NULL,
            cantidad_comprada DECIMAL(10, 3) NOT NULL,
            unidad_compra VARCHAR(50) NOT NULL,
            precio_costo_unitario_compra DECIMAL(10, 2) NOT NULL,
            subtotal_item DECIMAL(10, 2),
            FOREIGN KEY(compra_id) REFERENCES compras_proveedores(id) ON DELETE CASCADE,
            FOREIGN KEY(insumo_id) REFERENCES insumos(id) ON DELETE RESTRICT
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
        `);
        console.log("[DB:createTables] Tabla 'compras_proveedores_detalle' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS cierres_caja ...';
    try {
      await connection.query(`
      CREATE TABLE IF NOT EXISTS cierres_caja (
        id INT AUTO_INCREMENT PRIMARY KEY,
        fecha_hora DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        usuario_id INT NOT NULL,
        total_ventas_sistema DECIMAL(12, 2) NOT NULL,
        total_efectivo_sistema DECIMAL(12, 2) NOT NULL,
        total_tarjeta_sistema DECIMAL(12, 2) NOT NULL,
        total_otro_sistema DECIMAL(12, 2) NOT NULL,
        total_declarado_ars DECIMAL(12, 2) NOT NULL,
        total_declarado_usd DECIMAL(12, 2) NOT NULL,
        diferencia_ars DECIMAL(12, 2) NOT NULL,
        notas TEXT,
        FOREIGN KEY (usuario_id) REFERENCES usuarios(id) ON DELETE RESTRICT
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    `);
      console.log("[DB:createTables] Tabla 'cierres_caja' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

    currentQuery = 'CREATE TABLE IF NOT EXISTS cierre_caja_desglose ...';
    try {
      await connection.query(`
        CREATE TABLE IF NOT EXISTS cierre_caja_desglose (
          id INT AUTO_INCREMENT PRIMARY KEY,
          cierre_caja_id INT NOT NULL,
          moneda VARCHAR(3) NOT NULL COMMENT 'ARS o USD',
          denominacion DECIMAL(10, 2) NOT NULL COMMENT 'Ej: 1000, 50, 1',
          cantidad INT NOT NULL,
          FOREIGN KEY (cierre_caja_id) REFERENCES cierres_caja(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'cierre_caja_desglose' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }

        currentQuery = 'CREATE TABLE IF NOT EXISTS ticket_templates ...';
    try {
        await connection.query(`
        CREATE TABLE IF NOT EXISTS ticket_templates (
          id INT AUTO_INCREMENT PRIMARY KEY,
          template_name VARCHAR(100) NOT NULL UNIQUE,
          structure JSON NOT NULL,
          metadata JSON NULL,
          updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
      `);
      console.log("[DB:createTables] Tabla 'ticket_templates' verificada/creada con columna metadata.");
       try {
            await connection.query("ALTER TABLE ticket_templates ADD COLUMN metadata JSON NULL;");
            console.log("[DB:createTables] Columna 'metadata' añadida a 'ticket_templates' (o ya existía).");
       } catch(e) {
           if (e.code === 'ER_DUP_FIELDNAME') {
               console.warn("[DB:createTables] Advertencia: Columna 'metadata' ya existía en 'ticket_templates'.");
           } else {
               console.error("[DB:createTables] Error al añadir columna 'metadata' a 'ticket_templates':", e);
           }
       }

    } catch (e) { console.error(`[DB:createTables] ERROR al crear/modificar tabla 'ticket_templates':`, e); throw e; }



    currentQuery = 'CREATE TABLE IF NOT EXISTS company_profile ...';
    try {
        await connection.query(`
        CREATE TABLE IF NOT EXISTS company_profile (
          id INT PRIMARY KEY DEFAULT 1,
          business_name VARCHAR(255) NULL,
          legal_name VARCHAR(255) NULL,
          cuit VARCHAR(20) NULL,
          iibb VARCHAR(255) NULL, -- <<--- AGREGA ESTA LÍNEA
          start_date DATE NULL, -- <<--- ASEGÚRATE DE QUE ESTÉ ESTA LÍNEA
          address TEXT NULL,
          puntoVenta INT NULL -- <<--- AGREGA ESTA LÍNEA
        ) ENGINE=InnoDB;
      `);
      console.log("[DB:createTables] Tabla 'company_profile' verificada/creada.");
    } catch (e) { console.error(`[DB:createTables] ERROR en ${currentQuery}:`, e); throw e; }


    console.log("[DB:createTables] Proceso de verificación/creación de tablas finalizado.");

  } finally { // <-- ESTE ES EL FINALLY DEL TRY PRINCIPAL para liberar la conexión
    connection.release();
  }
}

// === REEMPLAZA COMPLETAMENTE TU FUNCIÓN insertDefaultTasas ACTUAL CON ESTA ===
async function insertDefaultTasas() {
  const connection = await pool.getConnection();
  try { // <-- TRY PRINCIPAL para la transacción
    await connection.beginTransaction();

    const clienteId = clienteData?.id || null;
    const clienteNombre = clienteData?.nombre || null;
    const clienteCuit = clienteData?.cuit || null;
    const clienteCondicionIva = clienteData?.condicionIVA || null;
    const clienteDomicilio = clienteData?.domicilio || null;

    const tasasPorDefecto = [
      { nombre: 'IVA 21%', valor: 0.21, desc: 'Tasa general de IVA' },
      { nombre: 'IVA 10.5%', valor: 0.105, desc: 'Tasa reducida para ciertos bienes/servicios' },
      { nombre: 'IVA 0%', valor: 0.0, desc: 'Exento de IVA' }
    ];
    console.log("[DB:insertDefaultTasas] Insertando tasas por defecto...");
    for (const tasa of tasasPorDefecto) {
      // No necesitamos try/catch DENTRO del for si toda la transacción se puede revertir
      // El catch principal abajo manejará cualquier error en las queries.
      const [rows] = await connection.execute('SELECT COUNT(*) as count FROM tasas_iva WHERE valor_tasa = ?', [tasa.valor]);
      if (rows[0].count === 0) {
        await connection.execute('INSERT INTO tasas_iva (nombre_tasa, valor_tasa, descripcion) VALUES (?, ?, ?)', [tasa.nombre, tasa.valor, tasa.desc]);
        console.log(`[DB:insertDefaultTasas] Tasa IVA '${tasa.nombre}' (${tasa.valor*100}%) insertada.`);
      } else {
         // console.log(`[DB:insertDefaultTasas] Tasa IVA '${tasa.nombre}' ya existe. No se inserta.`);
      }
    }
    await connection.commit(); // Confirmar si todo salió bien
    console.log("[DB:insertDefaultTasas] Proceso de tasas por defecto finalizado.");
  } catch (error) { // <-- CATCH PRINCIPAL para la transacción
    await connection.rollback(); // Revertir cambios si algo falló
    console.error("[DB:insertDefaultTasas] Error en transacción insertando tasas por defecto:", error);
    throw error; // Re-lanzar el error para que initializeDatabase lo capture
  } finally { // <-- FINALLY PRINCIPAL
    connection.release(); // Siempre liberar la conexión
  }
}

async function insertDefaultTemplates() {
  if (!pool) {
    console.error("[DB:insertDefaultTemplates] El pool de la base de datos no está inicializado.");
    return;
  }
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();

    const plantillasPorDefecto = [
      { name: 'facturaB', structure: defaultTemplateFacturaB },
      { name: 'facturaA', structure: defaultTemplateFacturaA },
      { name: 'comandaCocina', structure: defaultTemplateComandaCocina },
    ];

    console.log("[DB:insertDefaultTemplates] Insertando plantillas por defecto...");

    for (const plantilla of plantillasPorDefecto) {
      const [rows] = await connection.execute(
        'SELECT template_name FROM ticket_templates WHERE template_name = ?',
        [plantilla.name]
      );

      if (rows.length === 0) {
        await connection.execute(
          'INSERT INTO ticket_templates (template_name, structure) VALUES (?, ?)',
          [plantilla.name, JSON.stringify(plantilla.structure)]
        );
        console.log(`[DB:insertDefaultTemplates] Plantilla por defecto '${plantilla.name}' insertada.`);
      } else {
        //console.log(`[DB:insertDefaultTemplates] Plantilla por defecto '${plantilla.name}' ya existe. No se inserta.`);
      }
    }

    await connection.commit(); // Confirmar si todo salió bien
    console.log("[DB:insertDefaultTemplates] Proceso de plantillas por defecto finalizado.");
  } catch (error) { // <-- CATCH PRINCIPAL
    await connection.rollback(); // Revertir cambios si algo falló
    console.error("[DB:insertDefaultTemplates] Error en transacción insertando plantillas por defecto:", error);
    throw error; // Re-lanzar para que initializeDatabase lo capture
  } finally { // <-- FINALLY PRINCIPAL
    connection.release(); // Siempre liberar la conexión
  }
}

// === REEMPLAZA TODA TU FUNCIÓN insertDefaultTasas ACTUAL CON ESTA ===
async function insertDefaultTasas() {
  const connection = await pool.getConnection();
  try { // <-- TRY PRINCIPAL
    await connection.beginTransaction();
    const tasasPorDefecto = [
      { nombre: 'IVA 21%', valor: 0.21, desc: 'Tasa general de IVA' },
      { nombre: 'IVA 10.5%', valor: 0.105, desc: 'Tasa reducida para ciertos bienes/servicios' },
      { nombre: 'IVA 0%', valor: 0.0, desc: 'Exento de IVA' }
    ];
    console.log("[DB:insertDefaultTasas] Insertando tasas por defecto...");
    for (const tasa of tasasPorDefecto) {
      try { // <-- TRY para cada inserción
        const [rows] = await connection.execute('SELECT COUNT(*) as count FROM tasas_iva WHERE valor_tasa = ?', [tasa.valor]);
        if (rows[0].count === 0) {
          await connection.execute('INSERT INTO tasas_iva (nombre_tasa, valor_tasa, descripcion) VALUES (?, ?, ?)', [tasa.nombre, tasa.valor, tasa.desc]);
          console.log(`[DB:insertDefaultTasas] Tasa IVA '${tasa.nombre}' (${tasa.valor*100}%) insertada.`);
        } else {
           // console.log(`[DB:insertDefaultTasas] Tasa IVA '${tasa.nombre}' ya existe. No se inserta.`);
        }
      } catch (e) { // <-- CATCH para cada inserción
         console.error(`[DB:insertDefaultTasas] ERROR insertando tasa '${tasa.nombre}':`, e);
         throw e; // Lanza el error para que falle la transacción
      }
    }
    await connection.commit();
    console.log("[DB:insertDefaultTasas] Proceso de tasas por defecto finalizado.");
  } catch (error) { // <-- CATCH PRINCIPAL
    await connection.rollback();
    console.error("[DB:insertDefaultTasas] Error en transacción insertando tasas por defecto:", error);
    throw error;
  } finally {
    connection.release();
  }
}

async function insertDefaultTemplates() {
  if (!pool) {
    console.error("[DB:insertDefaultTemplates] El pool de la base de datos no está inicializado.");
    return;
  }
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();

    const plantillasPorDefecto = [
      { name: 'facturaB', structure: defaultTemplateFacturaB },
      { name: 'facturaA', structure: defaultTemplateFacturaA },
      { name: 'comandaCocina', structure: defaultTemplateComandaCocina },
    ];

    console.log("[DB:insertDefaultTemplates] Insertando plantillas por defecto...");

    for (const plantilla of plantillasPorDefecto) {
      try {
        const [rows] = await connection.execute(
          'SELECT template_name FROM ticket_templates WHERE template_name = ?',
          [plantilla.name]
        );

        if (rows.length === 0) {
          await connection.execute(
            'INSERT INTO ticket_templates (template_name, structure) VALUES (?, ?)',
            [plantilla.name, JSON.stringify(plantilla.structure)]
          );
          console.log(`[DB:insertDefaultTemplates] Plantilla por defecto '${plantilla.name}' insertada.`);
        } else {
        }
      } catch (e) {
         console.error(`[DB:insertDefaultTemplates] ERROR insertando plantilla '${plantilla.name}':`, e);
         throw e;
      }
    }

    await connection.commit();
    console.log("[DB:insertDefaultTemplates] Proceso de plantillas por defecto finalizado.");
  } catch (error) {
    await connection.rollback();
    console.error("[DB:insertDefaultTemplates] Error en transacción insertando plantillas por defecto:", error);
    throw error;
  } finally {
    connection.release();
  }
}


function getDefinedRoles() { return ['Noble', 'Capitalista', 'Indigente']; }

async function checkInitialAdminExists() {
  try {
    const [adminRows] = await pool.execute("SELECT id FROM usuarios WHERE role = 'Noble'");
    const [anyUserRows] = await pool.execute("SELECT id FROM usuarios");
    return { adminExists: adminRows.length > 0, anyUserExists: anyUserRows.length > 0, error: null };
  } catch (dbError) {
    console.error("[DB] Error en checkInitialAdminExists:", dbError);
    return { adminExists: false, anyUserExists: false, error: dbError.message };
  }
}

async function createUser(username, rawPassword, role) {
  const definedRoles = getDefinedRoles();
  if (!definedRoles.includes(role)) {
    throw new Error(`Rol "${role}" no es válido.`);
  }
  const saltRounds = 10;
  const hashedPassword = await bcrypt.hash(rawPassword, saltRounds);
  try {
    const [result] = await pool.execute('INSERT INTO usuarios (username, password, role) VALUES (?, ?, ?)', [username, hashedPassword, role]);
    return { id: result.insertId, username, role };
  } catch (error) {
    if (error.code === 'ER_DUP_ENTRY') {
      throw new Error(`El nombre de usuario "${username}" ya existe.`);
    }
    console.error("[DB] Error en createUser:", error);
    throw error;
  }
}

async function procesarVentaYActualizarStock(
  itemsVenta,
  totalVentaCalculado,
  netoGravadoCalculado,
  montoIvaCalculado,
  descuentoCalculado,
  usuarioId = null,
  metodoPago = null,
  pagoInfo = {},
  clienteData = null
) {
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();

    if (!itemsVenta || !Array.isArray(itemsVenta)) { 
      throw new Error("Items de venta no proporcionados o formato incorrecto");
    }

    if (isNaN(totalVentaCalculado)) { 
      throw new Error("Total de venta no es un número válido");
    }

    // Preparar datos del cliente para guardar en la venta
    const clienteId = clienteData?.id || null;
    const clienteNombre = clienteData?.nombre || 'Consumidor Final';
    const clienteCuit = clienteData?.cuit || null;
    const clienteCondicionIva = clienteData?.condicionIVA || 'Consumidor Final';
    const clienteDomicilio = clienteData?.domicilio || null;


    const [infoVenta] = await connection.execute(
      `INSERT INTO ventas (
        total_venta, neto_gravado, monto_iva, descuento,
        usuario_id, metodo_pago,
        monto_pagado_cliente, vuelto_entregado, notas,
        cliente_id, cliente_nombre, cliente_cuit, cliente_condicion_iva, cliente_domicilio
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        totalVentaCalculado,
        netoGravadoCalculado,
        montoIvaCalculado,
        descuentoCalculado,
        usuarioId,
        metodoPago,
        pagoInfo.montoPagadoClienteARS || null,
        pagoInfo.vueltoEntregadoARS || null,
        pagoInfo.notas || null,
        clienteId,
        clienteNombre,
        clienteCuit,
        clienteCondicionIva,
        clienteDomicilio
      ]
    );
    

    const ventaId = infoVenta.insertId;
    if (!ventaId) { throw new Error("No se pudo registrar la venta principal."); }
     console.log(`[DB] Venta con ID ${ventaId} insertada en ventas.`);

    // Lógica opcional para guardar el desglose de billetes en venta_pagos_desglose (tu código existente)
    // if (pagoInfo.desgloseARS && Array.isArray(pagoInfo.desgloseARS)) {
    //   for (const desglose of pagoInfo.desgloseARS) {
    //     if (desglose.cantidad > 0) {
    //       await connection.execute(
    //         'INSERT INTO venta_pagos_desglose (venta_id, moneda, denominacion, cantidad) VALUES (?, ?, ?, ?)',
    //         [ventaId, 'ARS', desglose.denominacion, desglose.cantidad]
    //       );
    //     }
    //   }
    // }
    // if (pagoInfo.desgloseUSD && Array.isArray(pagoInfo.desgloseUSD)) {
    //   for (const desglose of pagoInfo.desgloseUSD) {
    //     if (desglose.cantidad > 0) {
    //       await connection.execute(
    //         'INSERT INTO venta_pagos_desglose (venta_id, moneda, denominacion, cantidad) VALUES (?, ?, ?, ?)',
    //         [ventaId, 'USD', desglose.denominacion, desglose.cantidad]
    //       );
    //     }
    //   }
    // }
    // if (pagoInfo.customArsAmount && pagoInfo.customArsAmount > 0) {
    //      // Podrías registrar esto como un item 'VARIOS' o 'CUSTOM' en el desglose si es necesario
    // }


    for (const item of itemsVenta) {
      // Validar que item.tasa_iva_id llegue desde el frontend
      if (
           !item || // Asegurar que el item no sea null/undefined
           typeof item.cantidad !== 'number' || item.cantidad <= 0 ||
           typeof item.precioUnitarioFinal !== 'number' || // Usar precioUnitarioFinal
           item.tasa_iva_id === undefined // Checkear que venga el ID de la tasa IVA
         ) {
        console.error("Datos inválidos para el ítem de venta:", item);
        throw new Error(`Datos inválidos o faltantes para el ítem '${item?.descripcion_venta || item?.nombre || "sin nombre"}' en la venta.`);
      }

      // Recuperar nombre del producto si existe (podría ser nulo para items manuales)
      let nombreProducto = 'Desconocido';
       if (item.producto_id) {
            const [productoInfoRows] = await connection.execute('SELECT nombre FROM productos WHERE id = ?', [item.producto_id]);
            nombreProducto = productoInfoRows.length > 0 ? productoInfoRows[0].nombre : 'Desconocido';
       }


      // El subtotal ya debería venir calculado correctamente del frontend (cantidad * precioUnitarioFinal)
      const subtotalItem = Number(item.subtotal) || safeDecimalCalculation(item.cantidad, item.precioUnitarioFinal, 'multiply', 2);

      await connection.execute(
        'INSERT INTO venta_detalle (venta_id, producto_id, cantidad, precio_unitario_venta, costo_unitario_produccion, subtotal, descripcion_venta, tasa_iva_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
        [
          ventaId,
          item.producto_id || null,
          item.cantidad,
          item.precioUnitarioFinal,
          item.costo_unitario_produccion_venta || null,
          subtotalItem,
          item.descripcion_venta || JSON.stringify(item.configuracion || {}),
          item.tasa_iva_id
        ]
      );
     console.log(`[DB] Detalle para item ${item.producto_id || 'manual'} insertado.`);

      let todosLosInsumosADescontar = [];

      // 1. Devolver insumos de la receta base del producto (Solo si hay producto_id)
       if (item.producto_id) {
           const [recetaBaseItems] = await connection.execute(
             `SELECT prd.insumo_id, prd.cantidad_usada_en_receta
              FROM producto_receta_detalle prd
              WHERE prd.producto_id = ?`,
             [item.producto_id]
           );
           recetaBaseItems.forEach(insumoBase => {
               todosLosInsumosADescontar.push({
                   insumo_id: insumoBase.insumo_id,
                   cantidad_por_unidad: insumoBase.cantidad_usada_en_receta,
                   origen: `Receta Base (${nombreProducto})`
               });
           });
       }


      // 2. Devolver insumos de los aditivos, si los hay (Asumiendo que aditivosSeleccionados está en item.configuracion)
       const aditivosSeleccionados = Array.isArray(item.configuracion?.aditivos) ? item.configuracion.aditivos : [];

       if (aditivosSeleccionados.length > 0) {
           for (const aditivo of aditivosSeleccionados) {
               if (!aditivo.opcion_id) {
                   console.warn(`[Venta ID: ${ventaId}] Se encontró un aditivo sin opcion_id para el producto ${nombreProducto}. Omitiendo insumo descuento de aditivo.`);
                   continue;
               }
               const [recetaAditivoItems] = await connection.execute(
                   `SELECT insumo_id, cantidad FROM aditivo_opciones_recetas WHERE opcion_id = ?`,
                   [aditivo.opcion_id]
               );
               const nombreAditivo = aditivo.opcion_nombre || `Opción ID ${aditivo.opcion_id}`;

               recetaAditivoItems.forEach(insumoAditivo => {
                   todosLosInsumosADescontar.push({
                       insumo_id: insumoAditivo.insumo_id,
                       cantidad_por_unidad: insumoAditivo.cantidad,
                       origen: `Aditivo (${nombreAditivo})`
                   });
               });
           }
       }


      for (const insumoADescontar of todosLosInsumosADescontar) {
        const cantidadTotalADescontar = safeDecimalCalculation(
            insumoADescontar.cantidad_por_unidad,
            item.cantidad,
            'multiply',
            3 // Mantener alta precisión para el stock
        );

        if (isNaN(cantidadTotalADescontar) || cantidadTotalADescontar <= 0) continue;

         try {
             const [updateResult] = await connection.execute(
                 'UPDATE insumos SET cantidad_stock = cantidad_stock - ? WHERE id = ?',
                 [cantidadTotalADescontar, insumoADescontar.insumo_id]
             );

             if (updateResult.affectedRows === 0) {
                 console.warn(`[Venta ID: ${ventaId}] No se pudo actualizar el stock para el insumo ID ${insumoADescontar.insumo_id}. El insumo podría no existir.`);
                 // Opcional: Manejar esto como un error más grave si el insumo DEBE existir.
             }
             await connection.execute('INSERT INTO movimientos_stock (insumo_id, cantidad_movida, tipo_movimiento, referencia_id, notas) VALUES (?, ?, ?, ?, ?)',
               [insumoADescontar.insumo_id, -cantidadTotalADescontar, 'venta', ventaId, `Venta ID ${ventaId} - Item ${item.producto_id || 'manual'} - Origen: ${insumoADescontar.origen}`]);

         } catch (stockError) {
             console.error(`[Venta ID: ${ventaId}] Error descontando stock para insumo ${insumoADescontar.insumo_id}:`, stockError);
              // Decidir si un error de stock debe revertir la venta completa
              // throw stockError; // Descomentar para revertir si falla el stock
         }

    } // Fin for de insumos a descontar
} // Fin for de itemsVenta

  await connection.commit();
  console.log(`[DB] Transacción de venta ${ventaId} completada exitosamente.`);
  return { success: true, ventaId: ventaId, message: "Venta registrada y stock actualizado.", insertedVentaId: ventaId };
} catch (error) {
  await connection.rollback();
  console.error("[DB] Error en transacción procesarVentaYActualizarStock:", error);
  return { success: false, message: error.message || "Error crítico al procesar la venta." };
} finally {
  if (connection) connection.release();
}
}
// --- FIN DE LA FUNCIÓN procesarVentaYActualizarStock ---


// --- PEGAR AQUÍ LA FUNCIÓN actualizarVentaConDatosFiscales ---
// ESTA FUNCIÓN DEBE ESTAR FUERA DE procesarVentaYActualizarStock
async function actualizarVentaConDatosFiscales(ventaId, datosFiscales) {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();

        // Extraer datos fiscales
        const { cae, cae_vto, punto_venta_afip, afip_bill_number, tipo_comprobante_afip, afip_qr_data } = datosFiscales;

        // Actualizar la fila de la venta existente
        const [result] = await connection.execute(
          `UPDATE ventas
           SET cae = ?, cae_vto = ?, punto_venta_afip = ?, afip_bill_number = ?, tipo_comprobante_afip = ?, afip_qr_data = ?
           WHERE id = ?`,
          [
            cae || null,
            cae_vto ? new Date(cae_vto).toISOString().split('T')[0] : null, // Formato YYYY-MM-DD
            punto_venta_afip || null,
            afip_bill_number || null,
            tipo_comprobante_afip ? Number(tipo_comprobante_afip) : null,
            afip_qr_data || null,
            Number(ventaId)
          ]
        );

        if (result.affectedRows === 0) {
            console.warn(`[DB] Intento de actualizar venta ID ${ventaId} con datos fiscales, pero la venta no fue encontrada.`);
            await connection.rollback();
            return { success: false, message: `No se encontró la venta con ID ${ventaId} para actualizar.` };
        }

        await connection.commit();
        console.log(`[DB] Venta ${ventaId} actualizada con datos fiscales.`);
        return { success: true, message: "Venta actualizada con datos fiscales." };

    } catch (error) {
        await connection.rollback();
        console.error(`[DB] Error al actualizar venta ID ${ventaId} con datos fiscales:`, error);
        return { success: false, message: `Error al actualizar la venta con datos fiscales: ${error.message}` };
    } finally {
        if (connection) connection.release();
    }
}

module.exports = {
  initializeDatabase,
  getPool: () => {
    if (!pool) throw new Error("El pool de la base de datos no ha sido inicializado.");
    return pool;
  },
  checkInitialAdminExists,
  createUser,
  getDefinedRoles,
  procesarVentaYActualizarStock,
  actualizarVentaConDatosFiscales,
};

// src/electron/preload.js
const { contextBridge, ipcRenderer } = require('electron');

console.log('[Preload.js] Script de Preload INICIADO y EJECUTÁNDOSE.');

const exposedAPI = {

  //-- Cierre de caja --
  cierreGetDatosSistema: (usuarioId) => ipcRenderer.invoke('cierre:get-datos-sistema', usuarioId),
  cierreConfirmar: (datosCierre) => ipcRenderer.invoke('cierre:confirmar-cierre', datosCierre),

  // --- CONFIGURACIÓN DEL SISTEMA ---
  getCurrentHostname: () => ipcRenderer.invoke('get-current-hostname'),
  getSystemPrinters: () => ipcRenderer.invoke('get-system-printers'),

  //---Configuracion de perfil ---
  settingsGetCompanyProfile: () => ipcRenderer.invoke('settings:get-company-profile'),
  settingsSaveCompanyProfile: (data) => ipcRenderer.invoke('settings:save-company-profile', data),
  
  // Puestos de trabajo
  settingsGetWorkstations: () => ipcRenderer.invoke('settings:get-workstations'),
  settingsAddWorkstation: (data) => ipcRenderer.invoke('settings:add-workstation', data),
  
  // Impresoras registradas
  settingsGetPrinters: () => ipcRenderer.invoke('settings:get-printers'),
  settingsAddPrinter: (data) => ipcRenderer.invoke('settings:add-printer', data),
  
  // Asignaciones
  settingsGetAssignments: () => ipcRenderer.invoke('settings:get-assignments'),
  settingsSetAssignment: (data) => ipcRenderer.invoke('settings:set-assignment', data),

  // Insumos
  getInsumos: () => ipcRenderer.invoke('get-insumos'),
  addInsumo: (insumo) => ipcRenderer.invoke('add-insumo', insumo),
  updateInsumo: (insumoId, data) => ipcRenderer.invoke('update-insumo', insumoId, data),
  eliminarInsumo: (insumoId) => ipcRenderer.invoke('eliminar-insumo', insumoId),

  // Productos
  getProductos: () => ipcRenderer.invoke('get-productos'),
  getProductoById: (id) => ipcRenderer.invoke('get-producto-by-id', id),
  addProducto: (producto) => ipcRenderer.invoke('add-producto', producto),
  updateProducto: (productoId, data) => ipcRenderer.invoke('update-producto', productoId, data),
  eliminarProducto: (id) => ipcRenderer.invoke('eliminar-producto', id),

  // Receta
  getRecetaDeProducto: (productoId) => ipcRenderer.invoke('get-receta-de-producto', productoId),
  guardarProductoYReceta: (datos) => ipcRenderer.invoke('guardar-producto-y-receta', datos),

  // Tasas de IVA
  getTasasIVA: () => ipcRenderer.invoke('get-tasas-iva'),
  addTasaIVA: (tasaData) => ipcRenderer.invoke('add-tasa-iva', tasaData),

  // APIs DE AUTENTICACIÓN Y CONFIGURACIÓN
  'app:get-config-status': () => ipcRenderer.invoke('app:get-config-status'),
  'setup:as-server': (data) => ipcRenderer.invoke('setup:as-server', data),
  'setup:as-client': (data) => ipcRenderer.invoke('setup:as-client', data),
  checkInitialSetup: () => ipcRenderer.invoke('check-initial-setup'),

  // --- LÍNEAS AÑADIDAS ---
  login: (credentials) => ipcRenderer.invoke('login', credentials),
  createInitialAdmin: (adminData) => ipcRenderer.invoke('create-initial-admin', adminData),

  // APIs DE GESTIÓN DE USUARIOS (POR ADMIN)
  getAllUsers: () => ipcRenderer.invoke('get-all-users'),
  adminCreateUser: (userData) => ipcRenderer.invoke('admin-create-user', userData),
  adminUpdateUser: (userData) => ipcRenderer.invoke('admin-update-user', userData),
  adminDeleteUser: (ids) => ipcRenderer.invoke('admin-delete-user', ids),
  getDefinedRoles: () => ipcRenderer.invoke('get-defined-roles'),

  // API PARA EXPORTACIÓN
  exportarDatos: (opciones) => ipcRenderer.invoke('exportar-datos', opciones),

  // --- APIs PARA VENTAS ---
  getDatosParaVenta: () => ipcRenderer.invoke('get-datos-para-venta'),
  registrarVenta: (datosVenta) => ipcRenderer.invoke('registrar-venta', datosVenta),
  getVentasResumen: (filtros) => ipcRenderer.invoke('get-ventas-resumen', filtros),
  getCashDrawerStatus: () => ipcRenderer.invoke('get-cash-drawer-status'),
  anularVenta: (ventaId) => ipcRenderer.invoke('anular-venta', ventaId),

  // CATEGORIAS Y MODIFICADORES
  getCategorias: () => ipcRenderer.invoke('get-categorias'),
  getModificadores: () => ipcRenderer.invoke('get-modificadores'),
  getModificadoresDeProducto: (productoId) => ipcRenderer.invoke('get-modificadores-de-producto', productoId),
  setModificadoresParaProducto: (data) => ipcRenderer.invoke('set-modificadores-para-producto', data),
  addCategoria: (nombre) => ipcRenderer.invoke('add-categoria', nombre),
  addModificador: (data) => ipcRenderer.invoke('add-modificador', data),
  
  // APIs DE PROVEEDORES Y COMPRAS
  getProveedores: () => ipcRenderer.invoke('get-proveedores'),
  registrarCompraProveedor: (datosCompra) => ipcRenderer.invoke('registrar-compra-proveedor', datosCompra),
  
  // APIs PARA AFIP
  afipObtenerUltimoComprobante: (ptoVta, tipoCbte) => ipcRenderer.invoke('afip:obtener-ultimo-comprobante', { ptoVta, tipoCbte }),
  afipCrearFacturaYObtenerTicketData: (datosVenta) => ipcRenderer.invoke('afip:crear-factura-y-obtener-ticket-data', datosVenta),
  
  // FUNCIONES PARA BACKUP Y RESTORE
  backupDatabase: () => ipcRenderer.invoke('backup-database'),
  restoreDatabase: () => ipcRenderer.invoke('restore-database'),
  
  // FUNCIÓN PARA SOLICITAR REINICIO
  requestAppRestart: () => ipcRenderer.send('app-needs-restart'),

 // --- APIs PARA PLANTILLAS DE TICKETS ---
 'template:get-by-name': (templateName) => ipcRenderer.invoke('template:get-by-name', templateName),
 'template:save': (data) => ipcRenderer.invoke('template:save', data),

  // --- Productos ADITIVOS ---
  aditivosGetGrupos: () => ipcRenderer.invoke('aditivos:get-grupos'),
  aditivosCreateGrupo: (data) => ipcRenderer.invoke('aditivos:create-grupo', data),
  aditivosGetOpciones: () => ipcRenderer.invoke('aditivos:get-opciones'),
  aditivosCreateOpcion: (data) => ipcRenderer.invoke('aditivos:create-opcion', data),
  aditivosGetForProducto: (productoId) => ipcRenderer.invoke('aditivos:get-for-producto', productoId),
  aditivosSetForProducto: (data) => ipcRenderer.invoke('aditivos:set-for-producto', data),
  aditivosGetRecetaDeOpcion: (opcionId) => ipcRenderer.invoke('aditivos:get-receta-de-opcion', opcionId),
  aditivosSetRecetaDeOpcion: (data) => ipcRenderer.invoke('aditivos:set-receta-de-opcion', data),
  aditivosDeleteGrupo: (grupoId) => ipcRenderer.invoke('aditivos:delete-grupo', grupoId),
  aditivosDeleteOpcion: (opcionId) => ipcRenderer.invoke('aditivos:delete-opcion', opcionId),
  deleteModificador: (modificadorId) => ipcRenderer.invoke('delete-modificador', modificadorId),
  
  //--Cajero --
  getTotalVentasCajeroHoy: (usuarioId) => ipcRenderer.invoke('get-ventas-total-cajero-hoy', usuarioId),

  // --- APIs PARA CLIENTES ---
  'clients:get-all': () => ipcRenderer.invoke('clients:get-all'),
  'clients:get-by-id': (clientId) => ipcRenderer.invoke('clients:get-by-id', clientId),
  'clients:create': (clientData) => ipcRenderer.invoke('clients:create', clientData),
  'clients:update': (clientData) => ipcRenderer.invoke('clients:update', clientData),
  'clients:delete': (clientId) => ipcRenderer.invoke('clients:delete', clientId),
  'clients:search': (searchTerm) => ipcRenderer.invoke('clients:search', searchTerm),
  searchClients: (searchTerm) => ipcRenderer.invoke('clients:search', searchTerm), // Exponer searchClients para uso directo en el frontend

  // Eventos del Menú
  onExportInsumos: (callback) => {
    const subscription = (_event, ...args) => callback(...args);
    ipcRenderer.on('menu-exportar-insumos', subscription);
    return () => ipcRenderer.removeListener('menu-exportar-insumos', subscription);
  },
  onExportProductos: (callback) => {
    const subscription = (_event, ...args) => callback(...args);
    ipcRenderer.on('menu-exportar-productos', subscription);
    return () => ipcRenderer.removeListener('menu-exportar-productos', subscription);
  },
};

try {
  contextBridge.exposeInMainWorld('api', exposedAPI);
} catch (error) {
  console.error('[Preload.js] ERROR en contextBridge.exposeInMainWorld:', error);
}

// src/electron/main.js

const { app, ipcMain, BrowserWindow, dialog } = require('electron');
const path = require('path');
const fs = require('fs');
const mysql = require('mysql2/promise');

// Importaciones de la base de datos y helpers
const {
  initializeDatabase,
  createUser,
  checkInitialAdminExists,
  getDefinedRoles,
  procesarVentaYActualizarStock
} = require('./db/database');

const { createWindow } = require('./app-window');

// Importaciones de los Handlers IPC
const { registerInsumoHandlers } = require('./ipc-handlers/insumos-handlers');
const { registerProductoHandlers } = require('./ipc-handlers/productos-handlers');
const { registerRecetaHandlers } = require('./ipc-handlers/recetas-handlers');
const { registerTasaIvaHandlers } = require('./ipc-handlers/tasas-iva-handlers');
const { registerAuthHandlers } = require('./ipc-handlers/auth-handlers');
const { registerVentaHandlers } = require('./ipc-handlers/ventas-handlers');
const { registerExportHandlers } = require('./ipc-handlers/export-handlers');
const { registerProveedorHandlers } = require('./ipc-handlers/proveedores-handlers');
const { registerBackupRestoreHandlers } = require('./ipc-handlers/backup-restore-handlers');
const { registerAditivoHandlers } = require('./ipc-handlers/aditivos-handlers.js');
const { registerSettingsHandlers } = require('./ipc-handlers/settings-handlers');
const { registerCierreCajaHandlers } = require('./ipc-handlers/cierre-caja-handlers');
const { registerTemplateHandlers } = require('./ipc-handlers/templates-handlers.js');
const { registerClientHandlers } = require('./ipc-handlers/client-handlers');

const afipService = require('./afipService.js');

let mainWindow;
let pool = null;
let configFilePath = null;

app.whenReady().then(async () => {
    console.log('[Main] App Ready.');
  
    // VERIFICACIÓN DE CONFIGURACIÓN
    const userDataPath = app.getPath('userData');
    /* const configPath = path.join(userDataPath, 'config.json'); */
    configFilePath = path.join(userDataPath, 'config.json'); // <--- AÑADE ESTA LÍNEA
    console.log(`[Main] Definido path de configuración: ${configFilePath}`); // <--- AÑADE ESTA LÍNEA


    console.log(`[Main] Buscando configuración en: ${configFilePath}`); 
    const isConfigured = fs.existsSync(configFilePath); 
    console.log(`[Main] Resultado de verificación de existencia: ${isConfigured ? 'Encontrado' : 'NO encontrado'}`);
    
    if (isConfigured) {
      try {
        console.log('[Main] Inicializando base de datos MariaDB...');
        const config = JSON.parse(fs.readFileSync(configFilePath, 'utf-8'));
        
        // === INICIO DE MODIFICACIÓN ===
        try {
          pool = await initializeDatabase(config.database);
          
          // Verificar que la conexión funciona
          const conn = await pool.getConnection();
          await conn.ping();
          conn.release();
          
          console.log('[Main] Base de datos MariaDB inicializada y conexión verificada.');
        } catch (dbError) {
          console.error('[Main] ERROR al conectar a la base de datos:', dbError);
          dialog.showErrorBox(
            "Error de Conexión a DB", 
            `No se pudo conectar a la base de datos:\n\n${dbError.message}\n\nVerifica que:\n- El servidor MariaDB esté corriendo\n- Las credenciales en config.json sean correctas\n- La base de datos exista`
          );
          
          if (fs.existsSync(configFilePath)) {
            fs.unlinkSync(configFilePath);
          }
          app.quit();
          return;
        }
        // --- REGISTRO DE HANDLERS ---
        console.log('[Main] Registrando todos los handlers IPC...');
        registerInsumoHandlers(ipcMain, pool);
        registerProductoHandlers(ipcMain, pool);
        registerRecetaHandlers(ipcMain, pool);
        registerTasaIvaHandlers(ipcMain, pool);
        registerVentaHandlers(ipcMain, pool, { procesarVentaYActualizarStock });
        registerExportHandlers(ipcMain, pool);
        registerProveedorHandlers(ipcMain, pool);
        registerBackupRestoreHandlers(ipcMain); 
        registerAditivoHandlers(ipcMain, pool);
        registerCierreCajaHandlers(ipcMain, pool);
        registerTemplateHandlers(ipcMain, pool);
        registerClientHandlers(ipcMain, pool);
        
        console.log('[Main] Todos los grupos de handlers IPC de la app han sido invocados.');
  
        ipcMain.handle('get-system-printers', async (event) => {
            const win = BrowserWindow.fromWebContents(event.sender);
            if (!win) {
                console.error("Handler 'get-system-printers' no pudo encontrar la ventana de origen.");
                return { success: false, message: "No se pudo encontrar la ventana de la aplicación." };
            }
            try {
                const printers = await win.webContents.getPrintersAsync();
                return { success: true, printers: printers.map(p => ({ name: p.name, description: p.description, isDefault: p.isDefault })) };
            } catch (error) {
                console.error('Error al obtener impresoras:', error);
                return { success: false, message: error.message };
            }
        });
  
        // --- INICIALIZACIÓN DE AFIP ---
        try {
          console.log('[Main] Inicializando instancia de AFIP Service...');
          
          const [profileRows] = await pool.execute('SELECT cuit FROM company_profile WHERE id = 1');
          
          if (profileRows.length === 0 || !profileRows[0].cuit) {
              // En lugar de lanzar un error que detenga todo, solo advertimos.
              console.warn("[Main] ADVERTENCIA: No se encontró CUIT en el perfil de la empresa. La funcionalidad de AFIP estará deshabilitada hasta que se configure.");
          } else {
              const cuit = profileRows[0].cuit;
              await afipService.initialize(cuit);
              console.log('[Main] Conexión con AFIP (getServerStatus) OK.');
          }
        } catch (afipError) {
            console.error('[Main] ERROR inicializando AFIP Service:', afipError.message);
            // Este diálogo es útil para otros errores, como problemas de conexión de AFIP.
            dialog.showErrorBox("Error Conexión AFIP", `No se pudo inicializar la conexión con AFIP:\n\n${afipError.message}`);
        }
        
        // --- REGISTRO DE HANDLERS DE AFIP ---
        console.log('[Main] Registrando handlers IPC para AFIP...');
        ipcMain.handle('afip:obtener-ultimo-comprobante', async (event, { ptoVta, tipoCbte }) => {
          try {
            const afip = await afipService.getAfipInstance(); // Obtener la instancia
            const lastBill = await afip.ElectronicBilling.getLastVoucher(ptoVta, tipoCbte);
             console.log(`[Main] Último comprobante AFIP PV ${ptoVta} Tipo ${tipoCbte}: ${lastBill}`);
            // Devolver el número del último comprobante
            return { success: true, data: lastBill };
        } catch (error) {
            console.error('Error en afip:obtener-ultimo-comprobante:', error);
            return { success: false, message: error.message, error: error.message }; // Devolver el mensaje de error
        }
        });
        ipcMain.handle('afip:crear-factura-y-obtener-ticket-data', async (event, datosVentaOriginalCliente) => {
          const connection = await pool.getConnection(); // Asegúrate de tener una conexión o pool aquí
          try {
              // ... (tu lógica existente para llamar a la API de AFIP) ...
     
              // SUPONGAMOS que la respuesta de AFIP te da esto:
              const caeReal = '...' // Obtén CAE de la respuesta de AFIP
              const caeVtoReal = new Date('YYYY-MM-DD'); // Obtén Fecha Vto. de la respuesta de AFIP (como objeto Date si es posible)
              const numeroComprobanteReal = 12345678; // Obtén número de comprobante de AFIP
              const puntoVentaReal = 4; // Obtén punto de venta de AFIP o de la configuración
     
              // SUPONGAMOS que ya calculaste los datos para el QR:
              const qrDataFinal = '...' // String JSON para el QR
     
              // Y ya tienes los datos originales que pasaste:
              const ventaIdActual = datosVentaOriginalCliente.ventaId;
              const tipoComprobanteActual = datosVentaOriginalCliente.configuracionFactura.tipoComprobante; // 1 o 6
              const clienteDataOriginal = datosVentaOriginalCliente.cliente; // Los datos del cliente que pasaste desde Checkout
     
              // --- >> AÑADE ESTE BLOQUE << ---
              // Actualizar la venta en la DB con los datos fiscales
              await connection.execute(
                  `UPDATE ventas
                   SET cae = ?, cae_vto = ?, punto_venta_afip = ?, afip_bill_number = ?, tipo_comprobante_afip = ?, afip_qr_data = ?
                   WHERE id = ?`,
                  [
                      caeReal,
                      caeVtoReal, // Asegúrate de que sea un tipo compatible con DATE en MySQL (Date object o string 'YYYY-MM-DD')
                      String(puntoVentaReal).padStart(4, '0'), // Formato 4 dígitos
                      String(numeroComprobanteReal).padStart(8, '0'), // Formato 8 dígitos
                      tipoComprobanteActual,
                      qrDataFinal,
                      ventaIdActual
                  ]
              );
              console.log(`[Main] Venta ${ventaIdActual} actualizada en DB con datos AFIP.`);

               const ticketDataParaFrontend = {
                    comprobante: {
                        // ... (otros campos) ...
                        cae: caeReal,
                        caeFechaVencimiento: caeVtoReal,
                        puntoVenta: String(puntoVentaReal).padStart(4, '0'),
                        numeroTicket: String(numeroComprobanteReal).padStart(8, '0'),
                        tipoComprobante: tipoComprobanteActual === 1 ? 'FACTURA A' : 'FACTURA B',
                    },
                    qrData: qrDataFinal,
                    cliente: clienteDataOriginal,
               };
     
     
              return { success: true, ticketData: ticketDataParaFrontend };
     
          } catch (error) {
              console.error('Error en afip:crear-factura-y-obtener-ticket-data:', error);
              // ... (manejo de errores) ...
               return { success: false, message: 'Error al comunicarse con AFIP', error: error.message };
          } finally {
               if (connection) connection.release();
          }
      });
        console.log('[Main] Handlers IPC de AFIP registrados.');
  
      } catch (error) {
        console.error('[Main] ERROR CRÍTICO DURANTE LA INICIALIZACIÓN O REGISTRO DE HANDLERS:', error);
        dialog.showErrorBox(
            "Error Crítico de Aplicación",
            `No se pudo inicializar la aplicación debido a un error con la base de datos o configuración:\n\n${error.message}\n\nLa aplicación se cerrará.`
        );
        
        if (fs.existsSync(configFilePath)) {
          fs.unlinkSync(configFilePath);
          console.log(`[Main] config.json eliminado debido al error de inicialización.`);
        }

        app.quit();
        return;
      }
    } else {
      console.log('[Main] No se encontró configuración. Registrando handlers de SETUP.');
  
      ipcMain.handle('setup:as-server', async (event, { dbName, dbRootUser, dbRootPass }) => {
        console.log('[Setup Handler] Iniciando configuración como servidor...');
        let tempPool = null;
    
        try {
            // 1. Validaciones iniciales
            if (!dbName || !dbRootUser || !dbRootPass) {
                throw new Error('Todos los campos son obligatorios');
            }
    
            if (!/^[a-z0-9_]+$/i.test(dbName)) {
                throw new Error('El nombre de la BD solo puede contener letras, números y guiones bajos');
            }
    
            if (fs.existsSync(configFilePath)) {
                fs.unlinkSync(configFilePath);
                console.log('[Setup] config.json anterior eliminado');
            }

          console.log('[Setup] Intentando conectar con credenciales root a localhost...');
          tempPool = mysql.createPool({
              host: '127.0.0.1',
              port: 3306,
              user: dbRootUser,
              password: dbRootPass,
              multipleStatements: true,
              connectTimeout: 10000,
              connectionLimit: 1,
              authPlugins: {
                mysql_native_password: () => Buffer.from([0])
            }
          });

            console.log('[Setup] Conexión con MariaDB (root) verificada.');

            const testConn = await tempPool.getConnection();
            await testConn.ping();
            testConn.release();

            console.log('[Setup] Conexión con MariaDB verificada');
    
            const appDbUser = `app_${require('crypto').randomBytes(4).toString('hex')}`;
            const appDbPass = require('crypto').randomBytes(16).toString('hex');

            console.log(`[Setup] Credenciales de app generadas: Usuario=${appDbUser}, Contraseña=${appDbPass.substring(0, 4)}...`); 

            await tempPool.query(`
                DROP DATABASE IF EXISTS \`${dbName}\`;
                CREATE DATABASE \`${dbName}\` 
                CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
                
                DROP USER IF EXISTS '${appDbUser}'@'%';
                CREATE USER '${appDbUser}'@'%' 
                IDENTIFIED BY '${appDbPass}';
                
                GRANT ALL PRIVILEGES ON \`${dbName}\`.* 
                TO '${appDbUser}'@'%';
                
                FLUSH PRIVILEGES;
            `);
            console.log(`[Setup] BD '${dbName}' y usuario '${appDbUser}' creados`);
    
            await tempPool.end();
            tempPool = null;

            const newConfig = {
                database: {
                    host: '127.0.0.1',
                    port: 3306,
                    user: appDbUser,
                    password: appDbPass,
                    database: dbName,
                    authPlugins: {
                        mysql_native_password: () => Buffer.from([0])
                    }
                }
            };

            fs.writeFileSync(configFilePath, JSON.stringify(newConfig, null, 2)); 
            console.log('[Setup] config.json guardado correctamente');
    
            pool = await initializeDatabase(newConfig.database);
    
            return { 
                success: true,
                message: 'Configuración completada. La aplicación se reiniciará.',
                requiresAdminSetup: true
            };
    
        } catch (error) {
            console.error('[Setup] Error:', error);
            
            // Cerrar conexión si existe
            if (tempPool) {
                await tempPool.end().catch(e => console.error('Error cerrando pool:', e));
            }
            
            // Eliminar config.json si hubo error
            if (fs.existsSync(configFilePath)) {
              fs.unlinkSync(configFilePath);
              console.log('[Setup] config.json eliminado.');
          }
    
            // Mapear errores conocidos
            let friendlyMessage = error.message;
            switch (error.code) {
                case 'ER_ACCESS_DENIED_ERROR':
                    friendlyMessage = 'Credenciales incorrectas de MariaDB. Verifica usuario y contraseña root.';
                    break;
                case 'ER_DBACCESS_DENIED_ERROR':
                    friendlyMessage = 'El usuario no tiene permisos para crear bases de datos.';
                    break;
                case 'ECONNREFUSED':
                    friendlyMessage = 'No se pudo conectar a MariaDB. Verifica que el servicio esté corriendo.';
                    break;
                case 'ER_DB_CREATE_EXISTS':
                    friendlyMessage = 'Error al crear la base de datos. Intenta con otro nombre.';
                    break;
            }
    
            return { 
                success: false, 
                message: friendlyMessage,
                errorCode: error.code
            };
        }
    });
  
      // --- HANDLER PARA CONFIGURAR COMO CLIENTE ---
      ipcMain.handle('setup:as-client', async (event, { serverIp, dbName, dbUser, dbPassword }) => {
        console.log(`[Setup Handler] Recibida solicitud para configurar como CLIENTE a ${serverIp}`); 
          try {
              const clientConfig = {
                  host: serverIp,
                  port: 3306,
                  user: dbUser,
                  password: dbPassword,
                  database: dbName,
                  authPlugins: { mysql_native_password: () => Buffer.from([0]) }
              };
              console.log(`[Setup Server] DB creada y usuario seguro '${appDbUser}' configurado.`);

              const testPool = mysql.createPool(clientConfig);
              const connection = await testPool.getConnection();
              console.log('[Setup Client] ¡Prueba de conexión exitosa!');
              connection.release();
              await testPool.end();
  
              // 2. Si la conexión funcionó, guardamos esos datos en config.json
              const finalConfig = { database: clientConfig };
              fs.writeFileSync(configFilePath, JSON.stringify(finalConfig, null, 2));
              console.log(`[Setup Client] config.json de cliente guardado exitosamente.`);
              
              return { success: true };
  
          } catch (error) {
              console.error('[Setup Client] Error configurando como cliente:', error);
              let friendlyMessage = `No se pudo conectar: ${error.message}`;
              if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
                  friendlyMessage = `No se pudo encontrar el servidor en la IP: ${serverIp}. Verifica la IP y que la PC servidor esté encendida y en la misma red.`;
              } else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
                  friendlyMessage = 'Acceso denegado. Revisa el usuario y la contraseña de la base de datos que te dió el administrador.';
              }
              return { success: false, message: friendlyMessage };
          }
      });
  }
  
    // HANDLER PARA REINICIAR LA APLICACIÓN
    ipcMain.on('app-needs-restart', () => {
        console.log('[Main] Recibida solicitud para reiniciar la aplicación.');
        dialog.showMessageBox(mainWindow, {
            type: 'info',
            title: 'Reinicio Requerido',
            message: 'La aplicación se reiniciará para aplicar los cambios.',
            buttons: ['Aceptar']
        }).then(() => {
            app.relaunch();
            app.exit();
        });
    });
  
    console.log('[Main] Registrando handlers IPC críticos (disponibles siempre)...');
    
    // 1. REGISTRAMOS EL HANDLER QUE LE DICE A REACT SI HAY CONFIGURACIÓN
    ipcMain.handle('app:get-config-status', () => {
      console.log('[Main] Petición recibida: app:get-config-status');
      const isConfigured = fs.existsSync(configFilePath);
      console.log(`[Main] El sistema está configurado: ${isConfigured}`);
      return { isConfigured };
    });

    registerAuthHandlers(ipcMain, () => pool, { checkInitialAdminExists, createUser, getDefinedRoles });
    registerSettingsHandlers(ipcMain, () => pool);

    console.log('[Main] Creando ventana principal...');
    const preloadPath = path.join(__dirname, 'preload.js');
    mainWindow = createWindow(app.isPackaged, preloadPath);
    console.log('[Main] Ventana principal DEBERÍA haber sido creada.');
  
    if (mainWindow) {
        mainWindow.on('ready-to-show', () => {
            console.log('[Main] Evento "ready-to-show" de la ventana principal.');
        });
        mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
            console.error(`[Main] ERROR AL CARGAR URL en ventana principal: ${validatedURL}, Código: ${errorCode}, Desc: ${errorDescription}`);
            dialog.showErrorBox("Error de Carga", `No se pudo cargar la URL: ${validatedURL}\nDescripción: ${errorDescription}`);
        });
    } else {
        console.error('[Main] ERROR: La ventana principal (mainWindow) no fue creada.');
        dialog.showErrorBox("Error Crítico", "No se pudo crear la ventana principal de la aplicación.");
        app.quit();
        return;
    }
  
    // EVENTO 'ACTIVATE' PARA MACOS
    app.on('activate', () => {
      if (BrowserWindow.getAllWindows().length === 0) {
        console.log('[Main] Evento "activate": Creando nueva ventana.');
        const preloadPathActivate = path.join(__dirname, 'preload.js');
        mainWindow = createWindow(app.isPackaged, preloadPathActivate);
      }
    });
  
  });

app.on('window-all-closed', () => {
  console.log('[Main] Todas las ventanas cerradas.');
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

// Este evento se dispara justo antes de que la app se cierre
app.on('will-quit', async () => {
  try {
    // Ahora 'pool' es accesible aquí y podemos cerrarlo de forma segura
    if (pool) {
      await pool.end();
      console.log('[Main] Pool de conexiones de MariaDB cerrado.');
    } else {
        console.log('[Main] El pool de conexiones no estaba disponible o ya fue cerrado.');
    }
  } catch (error) {
    console.error('[Main] Error cerrando el pool de MariaDB:', error);
  }
});

process.on('uncaughtException', (error, origin) => {
  console.error(`[Main] Uncaught Exception en ${origin}:`, error);
  dialog.showErrorBox( "Error Inesperado", `Ha ocurrido un error inesperado:\n\n${error.message}`);
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('[Main] Unhandled Rejection en:', promise, 'razón:', reason);
  dialog.showErrorBox("Error Inesperado (Promesa)", `Ha ocurrido un error inesperado en una operación asíncrona:\n\n${String(reason)}`);
});

// Tus funciones helper al final del archivo
function formatearFechaAfipYyyymmddADdMmYyyy(fechaYyyymmdd) {
    if (!fechaYyyymmdd || String(fechaYyyymmdd).length !== 8) return "N/A";
    const sFecha = String(fechaYyyymmdd);
    const anio = sFecha.substring(0, 4);
    const mes = sFecha.substring(4, 6);
    const dia = sFecha.substring(6, 8);
    return `${dia}/${mes}/${anio}`;
}

function mapearTipoDocAfipATexto(tipoDocAfip) {
    switch (parseInt(tipoDocAfip)) {
        case 80: return "CUIT"; case 86: return "CUIL"; case 96: return "DNI";
        case 99: return ""; 
        default: return "Otros";
    }
}

function generarStringParaQR(cuitEmisor, fechaYyyymmdd, ptoVta, tipoCmp, nroCmp, importe, tipoDocRec, nroDocRec, cae) {
     if (!cuitEmisor) {
        console.error("Error generando QR: CUIT Emisor no definido.");
        return null; 
    }
    const fechaFormateada = `${fechaYyyymmdd.substring(0,4)}-${fechaYyyymmdd.substring(4,6)}-${fechaYyyymmdd.substring(6,8)}`;
    const qrJson = {
        "ver": 1, "fecha": fechaFormateada, "cuit": parseInt(cuitEmisor), "ptoVta": parseInt(ptoVta),
        "tipoCmp": parseInt(tipoCmp), "nroCmp": parseInt(nroCmp), "importe": parseFloat(importe.toFixed(2)),
        "moneda": "PES", "ctz": 1, "tipoDocRec": parseInt(tipoDocRec), "nroDocRec": parseInt(nroDocRec),
        "tipoCodAut": "E", "codAut": parseInt(cae)
    };
    return JSON.stringify(qrJson);
}

Solo quiero hacer ese cambio sin afectar todo lo demas.
Por cierto yo ya habia creado un componente search para eso pero nunca lo puse y de seguro no estaria funcionando es este.

// src/pages/ProductOptions/components/InputSearchEngine.jsx
import React, { useState, useMemo } from 'react';
import './InputSearchEngine.css';

const InputSearchEngine = ({ todosLosInsumos, insumosYaEnLista, onInsumoSeleccionado, disabled, placeholder }) => {
  const [terminoBusqueda, setTerminoBusqueda] = useState('');
  const [mostrarResultados, setMostrarResultados] = useState(false);

  // Filtramos los insumos que ya están en la receta del aditivo Y los que coinciden con la búsqueda
  const insumosFiltrados = useMemo(() => {
    const idsEnLista = new Set(insumosYaEnLista.map(item => item.insumo_id));
    const busquedaLower = terminoBusqueda.toLowerCase();

    return todosLosInsumos
      .filter(insumo => !idsEnLista.has(insumo.id)) // Excluir los ya añadidos
      .filter(insumo => insumo.nombre.toLowerCase().includes(busquedaLower)); // Filtrar por término de búsqueda
  }, [terminoBusqueda, todosLosInsumos, insumosYaEnLista]);

  const handleSelect = (insumo) => {
    onInsumoSeleccionado(insumo);
    setTerminoBusqueda('');
    setMostrarResultados(false);
  };

  return (
    <div className="buscador-insumos-container">
      <input
        type="text"
        className="buscador-insumos-input"
        placeholder={placeholder || "-- Buscar y añadir insumo --"}
        value={terminoBusqueda}
        onChange={e => setTerminoBusqueda(e.target.value)}
        onFocus={() => setMostrarResultados(true)}
        onBlur={() => setTimeout(() => setMostrarResultados(false), 200)} // Pequeño delay para permitir el click en la lista
        disabled={disabled}
      />
      {mostrarResultados && terminoBusqueda && insumosFiltrados.length > 0 && (
        <ul className="buscador-insumos-resultados">
          {insumosFiltrados.slice(0, 10).map(insumo => ( // Mostramos solo los primeros 10 para no saturar
            <li key={insumo.id} onMouseDown={() => handleSelect(insumo)}>
              {insumo.nombre} <small>({insumo.unidad_stock})</small>
            </li>
          ))}
        </ul>
      )}
       {mostrarResultados && terminoBusqueda && insumosFiltrados.length === 0 && (
         <div className="buscador-insumos-no-resultados">No se encontraron insumos</div>
       )}
    </div>
  );
};

export default InputSearchEngine;

/* src/pages/ProductOptions/components/BuscadorDeInsumos.css */
.buscador-insumos-container {
    position: relative;
    width: 100%;
  }
  
  .buscador-insumos-input {
    width: 100%;
    padding: 6px;
    background-color: #f1f3f5;
    border: 1px dashed #ccc;
    border-radius: 3px;
    box-sizing: border-box; /* Importante */
  }
  
  .buscador-insumos-resultados {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: white;
    border: 1px solid #ccc;
    border-top: none;
    border-radius: 0 0 4px 4px;
    list-style: none;
    padding: 0;
    margin: 0;
    max-height: 200px;
    overflow-y: auto;
    z-index: 1001; /* Debe estar por encima del resto del contenido del modal */
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
  }
  
  .buscador-insumos-resultados li {
    padding: 8px 12px;
    cursor: pointer;
    border-bottom: 1px solid #f0f0f0;
  }
  
  .buscador-insumos-resultados li:last-child {
    border-bottom: none;
  }
  
  .buscador-insumos-resultados li:hover {
    background-color: #e7f3ff;
  }
  
  .buscador-insumos-resultados li small {
      color: #888;
  }
  
  .buscador-insumos-no-resultados {
      position: absolute;
      top: 100%;
      left: 0;
      right: 0;
      background: white;
      border: 1px solid #ccc;
      padding: 8px 12px;
      color: #777;
      font-style: italic;
      z-index: 1001;
  }