'use strict';

const sql = require('mssql');
const { qname, inspectTables, requireColumns } = require('../softrestaurantIntrospection');
const { validatePriceUpdate, commandError } = require('../commandHandlers/schemas');
const { createMapper, schemaMismatch } = require('./baseMapper');

async function validate(payload = {}, config = {}) {
  const data = validatePriceUpdate(payload);
  const configuredEmpresa = config.softrestaurantIdEmpresa || process.env.SOFTRESTAURANT_IDEMPRESA || null;
  const payloadEmpresa = payload.idempresa || payload.softrestaurant_idempresa || null;
  if (configuredEmpresa && payloadEmpresa && String(configuredEmpresa) !== String(payloadEmpresa)) {
    throw commandError('branch_idempresa_mismatch', 'idempresa del comando no coincide con la sucursal configurada');
  }
  return {
    idproducto: data.idproducto,
    precio: data.precio1,
    idempresa: payloadEmpresa || configuredEmpresa,
    dry_run: payload.dry_run !== false,
  };
}

async function inspect(pool) {
  return inspectTables(pool, {
    productos: ['idproducto', 'descripcion'],
    productosdetalle: ['idproducto', 'idempresa', 'precio'],
  });
}

async function findProduct(pool, payload) {
  const request = pool.request().input('idproducto', sql.NVarChar(80), payload.idproducto);
  let where = 'pd.idproducto=@idproducto';
  if (payload.idempresa) {
    request.input('idempresa', sql.NVarChar(80), payload.idempresa);
    where += ' AND pd.idempresa=@idempresa';
  }
  const result = await request.query(`
    SELECT TOP 5 p.idproducto, p.descripcion, pd.idempresa, pd.precio
    FROM ${qname('productos')} p
    LEFT JOIN ${qname('productosdetalle')} pd ON pd.idproducto=p.idproducto
    WHERE ${where}
    ORDER BY CASE WHEN pd.idempresa IS NULL THEN 1 ELSE 0 END, pd.idempresa
  `);
  return result.recordset;
}

async function dryRun({ payload, pool }) {
  const metadata = await inspect(pool);
  const errors = [
    ...requireColumns(metadata, 'productos', ['idproducto']),
    ...requireColumns(metadata, 'productosdetalle', ['idproducto', 'idempresa', 'precio']),
  ];
  if (errors.length) schemaMismatch(errors);
  const rows = await findProduct(pool, payload);
  if (!rows.length) throw commandError('product_price_not_found', `Producto/precio ${payload.idproducto} no encontrado`);
  if (!payload.idempresa && rows.length > 1) {
    throw commandError('ambiguous_product_price', 'idempresa requerido: el producto tiene precios en mas de una empresa');
  }
  const target = rows[0];
  return {
    ok: true,
    dry_run: true,
    entity_type: 'product_price',
    entity_id: `${target.idempresa || payload.idempresa || 'unknown'}:${payload.idproducto}`,
    current_price: Number(target.precio || 0),
    planned_price: payload.precio,
    idempresa: target.idempresa || payload.idempresa || null,
    price_table: 'productosdetalle',
    price_column: 'precio',
  };
}

async function execute({ payload, pool, tx }) {
  const plan = await dryRun({ payload, pool });
  const idempresa = plan.idempresa;
  if (!idempresa) throw commandError('invalid_payload', 'idempresa requerido para escritura real de precio');
  await tx.request()
    .input('idproducto', sql.NVarChar(80), payload.idproducto)
    .input('idempresa', sql.NVarChar(80), idempresa)
    .input('precio', sql.Money, payload.precio)
    .query(`UPDATE ${qname('productosdetalle')} SET precio=@precio WHERE idproducto=@idproducto AND idempresa=@idempresa`);
  return {
    ok: true,
    dry_run: false,
    entity_type: 'product_price',
    entity_id: `${idempresa}:${payload.idproducto}`,
    applied: { idempresa, idproducto: payload.idproducto, precio: payload.precio },
  };
}

const mapper = createMapper({ commandType: 'CHANGE_PRODUCT_PRICE', validate, dryRun, execute });

module.exports = { changeProductPrice: mapper.run, mapper, validate, dryRun, execute, inspect };
