const express = require('express');
const router = express.Router();
const db = require('../config/db');
const dh = require('./distinctHelper');

var clDbType = (process.env.DB_TYPE || process.env.MODO_ERP || 'mssql').toLowerCase();
var clColCondicion = 'cp.nombre';


const LIMITES = {
    razon_social: 100,
    direccion: 200,
    contacto_nombre: 100,
    email: 100,
    num_documento: 20,
    telefono: 20,
    celular: 20,
    notas: 500
};

function validarLongitud(body) {
    var errores = [];
    var camposTexto = [
        'razon_social', 'direccion', 'contacto_nombre', 'email',
        'num_documento', 'telefono', 'celular', 'notas'
    ];
    for (var i = 0; i < camposTexto.length; i++) {
        var campo = camposTexto[i];
        if (body[campo] && body[campo].length > LIMITES[campo]) {
            errores.push(campo + ' supera el límite de ' + LIMITES[campo] + ' caracteres');
        }
    }
    return errores;
}

var COLUMNAS = {
    cod_cliente:     { sql: 'c.cod_cliente',           tipo: 'string' },
    razon_social:    { sql: 'c.razon_social',          tipo: 'string' },
    num_documento:   { sql: 'c.num_documento',          tipo: 'string' },
    contacto_nombre: { sql: 'c.contacto_nombre',        tipo: 'string' },
    telefono:        { sql: 'c.telefono',               tipo: 'string' },
    celular:         { sql: 'c.celular',                tipo: 'string' },
    email:           { sql: 'c.email',                  tipo: 'string' },
    vendedor:        { sql: 'v.nombre',                 tipo: 'string' },
    condicion:       { sql: clColCondicion,               tipo: 'string' },
    estado:          { sql: 'c.estado',                 tipo: 'int'    }
};

// ============================================================
// GET /api/clientes — Listar con filtros, sort y paginación
// ============================================================
router.get('/clientes', async function(req, res) {
    try {
        var idEmpresa = req.query.id_empresa;
        var buscar = req.query.buscar || '';
        var estado = req.query.estado;
        var page = parseInt(req.query.page) || 1;
        var limit = req.query.limit !== undefined ? parseInt(req.query.limit) : 20;
        var offset = (page - 1) * limit;
        var sinPaginacion = limit <= 0;
        var sort = req.query.sort || 'cod_cliente';
        var order = (req.query.order || 'ASC').toUpperCase();
        var filtros = req.query.filtros;

        var where = 'WHERE c.id_empresa = @id_empresa';
        var params = {
            id_empresa: { type: db.sql.Int, value: parseInt(idEmpresa) }
        };

        var idSucursal = req.query.id_sucursal ? parseInt(req.query.id_sucursal) : null;
        if (idSucursal) {
            where += ' AND c.id_sucursal = @id_sucursal';
            params.id_sucursal = { type: db.sql.Int, value: idSucursal };
        }

        if (buscar) {
            where += ' AND (c.razon_social LIKE @buscar OR c.num_documento LIKE @buscar OR c.cod_cliente LIKE @buscar)';
            params.buscar = { type: db.sql.VarChar(100), value: '%' + buscar + '%' };
        }

        if (estado === '1') {
            where += ' AND c.estado = 1';
        } else if (estado === '0') {
            where += ' AND c.estado = 0';
        }

        var columnFilters = {};
        if (filtros) {
            try { columnFilters = JSON.parse(filtros); } catch (_) {}
        }
        var idxFiltro = 0;
        Object.keys(columnFilters).forEach(function(col) {
            var valores = columnFilters[col];
            if (!valores || valores.length === 0) return;
            var colMeta = COLUMNAS[col];
            if (!colMeta) return;

            var vals = valores.split('\x01').map(function(v) { return v.trim(); }).filter(Boolean);
            if (vals.length === 0) return;

            var paramName = 'f' + idxFiltro;
            if (vals.length === 1) {
                where += ' AND ' + colMeta.sql + ' = @' + paramName;
                params[paramName] = colMeta.tipo === 'int'
                    ? { type: db.sql.Int, value: parseInt(vals[0]) }
                    : { type: db.sql.NVarChar(200), value: vals[0] };
            } else {
                var placeholders = vals.map(function(v, i) {
                    var pn = paramName + '_' + i;
                    params[pn] = colMeta.tipo === 'int'
                        ? { type: db.sql.Int, value: parseInt(v) }
                        : { type: db.sql.NVarChar(200), value: v };
                    return '@' + pn;
                });
                where += ' AND ' + colMeta.sql + ' IN (' + placeholders.join(',') + ')';
            }
            idxFiltro++;
        });

        var colMapClientes = {};
        Object.keys(COLUMNAS).forEach(function(k) { colMapClientes[k] = COLUMNAS[k].sql; });
        var joinsClientes = ' LEFT JOIN vendedores v ON c.id_empresa = v.id_empresa AND c.id_vendedor = v.id_vendedor LEFT JOIN condiciones_pago cp ON c.id_empresa = cp.id_empresa AND c.id_condicion = cp.id_condicion';
        if (await dh.tryDistinct(req, res, { db, table: 'clientes', alias: 'c', joins: joinsClientes, colMap: colMapClientes, where, params, bitColumns: ['estado'] })) return;

        var sortSql = 'c.cod_cliente ASC';
        if (sort && COLUMNAS[sort]) {
            var dir = order === 'DESC' ? 'DESC' : 'ASC';
            sortSql = COLUMNAS[sort].sql + ' ' + dir;
        }

        var joins = ' LEFT JOIN vendedores v ON c.id_empresa = v.id_empresa AND c.id_vendedor = v.id_vendedor';
        joins += ' LEFT JOIN condiciones_pago cp ON c.id_empresa = cp.id_empresa AND c.id_condicion = cp.id_condicion';
        var sqlCount = 'SELECT COUNT(*) as total FROM clientes c' + joins + ' ' + where;

        var countResult = await db.query(sqlCount, params);
        var total = countResult[0].total;
        var totalPaginas = Math.ceil(total / limit);

        var selectCols = `
            c.id_cliente, c.id_sucursal, c.cod_cliente, c.razon_social,
            c.tipo_documento, c.num_documento, c.direccion,
            c.cod_ubigeo, c.telefono, c.celular, c.email,
            c.contacto_nombre,
            c.id_condicion, ${clColCondicion} AS condicion_nombre,
            c.id_vendedor, v.nombre AS vendedor_nombre,
            c.lim_credito, c.lim_dias, c.lim_docs,
            c.moneda_credito,
            c.retencion, c.percepcion,
            c.notas, c.estado
        `;

        var sqlData;
        if (sinPaginacion) {
            sqlData = 'SELECT ' + selectCols + ' FROM clientes c' + joins + ' ' + where + ' ORDER BY ' + sortSql;
        } else {
            sqlData = 'SELECT ' + selectCols + ' FROM clientes c' + joins + ' ' + where + ' ORDER BY ' + sortSql + ' OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY';
            params.offset = { type: db.sql.Int, value: offset };
            params.limit = { type: db.sql.Int, value: limit };
        }

        var data = await db.query(sqlData, params);

        res.json({
            ok: true,
            data: data,
            total: total,
            totalPaginas: totalPaginas,
            page: page
        });
    } catch (error) {
        console.error('[CLIENTES] Error al listar:', error.message);
        res.status(500).json({ ok: false, mensaje: 'Error al consultar clientes' });
    }
});

// ============================================================
// GET /api/clientes/valores-filtro — Valores únicos para filtros
// ============================================================
router.get('/clientes/valores-filtro', async function(req, res) {
    try {
        var idEmpresa = req.query.id_empresa;
        if (!idEmpresa) {
            return res.json({ ok: false, mensaje: 'id_empresa requerido' });
        }

        var sqlEstado = "SELECT DISTINCT CAST(c.estado AS VARCHAR) AS valor, CASE WHEN c.estado=1 THEN 'Activo' ELSE 'Inactivo' END AS texto FROM clientes c WHERE c.id_empresa = @id ORDER BY c.estado";
        var estadoRows = await db.query(sqlEstado, { id: { type: db.sql.Int, value: parseInt(idEmpresa) } });

        var sqlVend = "SELECT DISTINCT CAST(c.id_vendedor AS VARCHAR) AS valor, v.nombre AS texto FROM clientes c JOIN vendedores v ON c.id_empresa = v.id_empresa AND c.id_vendedor = v.id_vendedor WHERE c.id_empresa = @id ORDER BY v.nombre";
        var vendRows = await db.query(sqlVend, { id: { type: db.sql.Int, value: parseInt(idEmpresa) } });

        var sqlCon = "SELECT DISTINCT CAST(c.id_condicion AS VARCHAR) AS valor, " + clColCondicion + " AS texto FROM clientes c JOIN condiciones_pago cp ON c.id_empresa = cp.id_empresa AND c.id_condicion = cp.id_condicion WHERE c.id_empresa = @id ORDER BY " + clColCondicion + "";
        var conRows = await db.query(sqlCon, { id: { type: db.sql.Int, value: parseInt(idEmpresa) } });

        res.json({
            ok: true,
            data: {
                estado: estadoRows,
                vendedor: vendRows,
                condicion: conRows
            }
        });
    } catch (error) {
        console.error('[CLIENTES] Error al obtener valores filtro:', error.message);
        res.json({ ok: false, mensaje: 'Error al obtener valores para filtros' });
    }
});

// ============================================================
// GET /api/clientes/:id — Obtener uno por ID
// ============================================================
router.get('/clientes/:id', async function(req, res) {
    try {
        var idEmpresa = req.query.id_empresa;
        if (!idEmpresa) {
            return res.status(400).json({ ok: false, mensaje: 'id_empresa es requerido' });
        }
        var sqlStr = `
            SELECT c.id_cliente, c.id_empresa, c.id_sucursal, c.cod_cliente, c.razon_social,
                   c.tipo_documento, c.num_documento, c.direccion, c.cod_ubigeo,
                   c.telefono, c.celular, c.email, c.contacto_nombre,
                   c.id_condicion, ${clColCondicion} AS condicion_nombre,
                   c.id_vendedor, v.nombre AS vendedor_nombre,
                   c.lim_credito, c.lim_dias, c.lim_docs,
                   c.moneda_credito,
                   c.retencion, c.percepcion,
                   c.notas,
                   c.estado
            FROM clientes c
            LEFT JOIN condiciones_pago cp ON c.id_empresa = cp.id_empresa AND c.id_condicion = cp.id_condicion
            LEFT JOIN vendedores v ON c.id_empresa = v.id_empresa AND c.id_vendedor = v.id_vendedor
            WHERE c.id_cliente = @id AND c.id_empresa = @id_empresa
        `;
        var data = await db.query(sqlStr, {
            id: { type: db.sql.Int, value: parseInt(req.params.id) },
            id_empresa: { type: db.sql.Int, value: parseInt(idEmpresa) }
        });

        if (data.length === 0) {
            return res.status(404).json({ ok: false, mensaje: 'Cliente no encontrado' });
        }

        res.json({ ok: true, data: data[0] });
    } catch (error) {
        console.error('[CLIENTES] Error al obtener:', error.message);
        res.status(500).json({ ok: false, mensaje: 'Error al consultar cliente' });
    }
});

// ============================================================
// POST /api/clientes — Crear nuevo
// ============================================================
router.post('/clientes', async function(req, res) {
    try {
        var errores = validarLongitud(req.body);
        if (errores.length > 0) {
            return res.status(400).json({ ok: false, mensaje: errores.join('. ') });
        }

        var sqlCorrelativo = `
            SELECT ISNULL(MAX(CAST(cod_cliente AS INT)), 0) + 1 as siguiente
            FROM clientes
            WHERE id_empresa = @id_empresa
        `;
        var corrResult = await db.query(sqlCorrelativo, {
            id_empresa: { type: db.sql.Int, value: req.body.id_empresa }
        });
        var siguiente = corrResult[0].siguiente;
        var codCliente = String(siguiente).padStart(6, '0');

        var sqlInsert = `
            INSERT INTO clientes (
                id_empresa, id_sucursal, cod_cliente, razon_social, tipo_documento,
                num_documento, direccion, cod_ubigeo, telefono, celular,
                email, contacto_nombre,
                id_condicion, id_vendedor,
                lim_credito, lim_dias, lim_docs,
                moneda_credito,
                retencion, percepcion,
                notas,
                estado, creado_por, fecha_creacion
            ) VALUES (
                @id_empresa, @id_sucursal, @cod_cliente, @razon_social, @tipo_documento,
                @num_documento, @direccion, @cod_ubigeo, @telefono, @celular,
                @email, @contacto_nombre,
                @id_condicion, @id_vendedor,
                @lim_credito, @lim_dias, @lim_docs,
                @moneda_credito,
                @retencion, @percepcion,
                @notas,
                1, @creado_por, SYSDATETIME()
            )
        `;
        await db.execute(sqlInsert, {
            id_empresa: { type: db.sql.Int, value: req.body.id_empresa },
            id_sucursal: { type: db.sql.Int, value: req.body.id_sucursal || null },
            cod_cliente: { type: db.sql.Char(6), value: codCliente },
            razon_social: { type: db.sql.VarChar(200), value: req.body.razon_social },
            tipo_documento: { type: db.sql.Char(2), value: req.body.tipo_documento },
            num_documento: { type: db.sql.VarChar(20), value: req.body.num_documento },
            direccion: { type: db.sql.VarChar(200), value: req.body.direccion },
            cod_ubigeo: { type: db.sql.Char(6), value: req.body.cod_ubigeo },
            telefono: { type: db.sql.VarChar(20), value: req.body.telefono },
            celular: { type: db.sql.VarChar(20), value: req.body.celular },
            email: { type: db.sql.VarChar(100), value: req.body.email },
            contacto_nombre: { type: db.sql.VarChar(100), value: req.body.contacto_nombre },
            id_condicion: { type: db.sql.Int, value: req.body.id_condicion || null },
            id_vendedor: { type: db.sql.Int, value: req.body.id_vendedor || null },
            lim_credito: { type: db.sql.Decimal(12,2), value: req.body.lim_credito || 0 },
            lim_dias: { type: db.sql.Int, value: req.body.lim_dias || 0 },
            lim_docs: { type: db.sql.Int, value: req.body.lim_docs || 0 },
            moneda_credito: { type: db.sql.Char(2), value: req.body.moneda_credito || 'MN' },
            retencion: { type: db.sql.Bit, value: req.body.retencion ? 1 : 0 },
            percepcion: { type: db.sql.Bit, value: req.body.percepcion ? 1 : 0 },
            notas: { type: db.sql.NVarChar(500), value: req.body.notas || null },
            creado_por: { type: db.sql.Int, value: req.body.creado_por }
        });

        res.json({
            ok: true,
            mensaje: 'Cliente registrado correctamente',
            data: { cod_cliente: codCliente }
        });
    } catch (error) {
        console.error('[CLIENTES] Error al crear:', error.message);
        res.status(500).json({ ok: false, mensaje: 'Error al registrar cliente' });
    }
});

// ============================================================
// PUT /api/clientes — Actualizar existente
// ============================================================
router.put('/clientes', async function(req, res) {
    try {
        var errores = validarLongitud(req.body);
        if (errores.length > 0) {
            return res.status(400).json({ ok: false, mensaje: errores.join('. ') });
        }

        var idEmpresa = req.body.id_empresa;
        if (!idEmpresa) {
            return res.status(400).json({ ok: false, mensaje: 'id_empresa es requerido' });
        }

        var sqlUpdate = `
            UPDATE clientes SET
                razon_social = @razon_social,
                tipo_documento = @tipo_documento,
                num_documento = @num_documento,
                direccion = @direccion,
                cod_ubigeo = @cod_ubigeo,
                telefono = @telefono,
                celular = @celular,
                email = @email,
                contacto_nombre = @contacto_nombre,
                id_condicion = @id_condicion,
                id_vendedor = @id_vendedor,
                lim_credito = @lim_credito,
                lim_dias = @lim_dias,
                lim_docs = @lim_docs,
                moneda_credito = @moneda_credito,
                retencion = @retencion,
                percepcion = @percepcion,
                notas = @notas,
                estado = @estado,
                modificado_por = @modificado_por,
                fecha_modificacion = SYSDATETIME()
            WHERE id_cliente = @id_cliente AND id_empresa = @id_empresa
        `;
        var filas = await db.execute(sqlUpdate, {
            id_cliente: { type: db.sql.Int, value: req.body.id_cliente },
            id_empresa: { type: db.sql.Int, value: parseInt(idEmpresa) },
            razon_social: { type: db.sql.VarChar(200), value: req.body.razon_social },
            tipo_documento: { type: db.sql.Char(2), value: req.body.tipo_documento },
            num_documento: { type: db.sql.VarChar(20), value: req.body.num_documento },
            direccion: { type: db.sql.VarChar(200), value: req.body.direccion },
            cod_ubigeo: { type: db.sql.Char(6), value: req.body.cod_ubigeo },
            telefono: { type: db.sql.VarChar(20), value: req.body.telefono },
            celular: { type: db.sql.VarChar(20), value: req.body.celular },
            email: { type: db.sql.VarChar(100), value: req.body.email },
            contacto_nombre: { type: db.sql.VarChar(100), value: req.body.contacto_nombre },
            id_condicion: { type: db.sql.Int, value: req.body.id_condicion || null },
            id_vendedor: { type: db.sql.Int, value: req.body.id_vendedor || null },
            lim_credito: { type: db.sql.Decimal(12,2), value: req.body.lim_credito || 0 },
            lim_dias: { type: db.sql.Int, value: req.body.lim_dias || 0 },
            lim_docs: { type: db.sql.Int, value: req.body.lim_docs || 0 },
            moneda_credito: { type: db.sql.Char(2), value: req.body.moneda_credito || 'MN' },
            retencion: { type: db.sql.Bit, value: req.body.retencion ? 1 : 0 },
            percepcion: { type: db.sql.Bit, value: req.body.percepcion ? 1 : 0 },
            notas: { type: db.sql.NVarChar(500), value: req.body.notas || null },
            estado: { type: db.sql.Int, value: req.body.estado },
            modificado_por: { type: db.sql.Int, value: req.body.modificado_por }
        });

        if (filas === 0) {
            return res.status(404).json({ ok: false, mensaje: 'Cliente no encontrado' });
        }

        res.json({ ok: true, mensaje: 'Cliente actualizado correctamente' });
    } catch (error) {
        console.error('[CLIENTES] Error al actualizar:', error.message);
        res.status(500).json({ ok: false, mensaje: 'Error al actualizar cliente' });
    }
});

// ============================================================
// DELETE /api/clientes/:id — Eliminación condicional
// ============================================================
router.delete('/clientes/:id', async function(req, res) {
    try {
        var id = parseInt(req.params.id);
        var idEmpresa = req.query.id_empresa;
        if (!idEmpresa) {
            return res.status(400).json({ ok: false, mensaje: 'id_empresa es requerido' });
        }

        // Verificar si tiene guías asociadas
        var refs;
        var refDetalle = { guias_remision: 0 };
        try {
            var refResult = await db.query(
                 `SELECT
                    ISNULL((SELECT COUNT(*) FROM guias_remision WHERE id_cliente = @id AND id_empresa = @id_empresa), 0) as guias_remision`,
                {
                    id: { type: db.sql.Int, value: id },
                    id_empresa: { type: db.sql.Int, value: parseInt(idEmpresa) }
                }
            );
            if (refResult && refResult[0]) {
                refDetalle = refResult[0];
                refs = [{ cnt: refDetalle.guias_remision }];
            }
        } catch (e) {
            if (String(e.message || e).indexOf('Invalid object name') >= 0) {
                refs = [{ cnt: 0 }];
            } else {
                throw e;
            }
        }

        if (refs && refs[0] && refs[0].cnt > 0) {
            // Tiene movimientos → solo desactivar
            var filas = await db.execute(
                'UPDATE clientes SET estado = 0, fecha_modificacion = SYSDATETIME() WHERE id_cliente = @id AND id_empresa = @id_empresa',
                {
                    id: { type: db.sql.Int, value: id },
                    id_empresa: { type: db.sql.Int, value: parseInt(idEmpresa) }
                }
            );
            if (filas === 0) {
                return res.status(404).json({ ok: false, mensaje: 'Cliente no encontrado' });
            }
            res.json({ ok: true, mensaje: 'Cliente desactivado (tiene movimientos asociados)' });
        } else {
            // Sin movimientos → eliminar físicamente
            var filas = await db.execute(
                'DELETE FROM clientes WHERE id_cliente = @id AND id_empresa = @id_empresa',
                {
                    id: { type: db.sql.Int, value: id },
                    id_empresa: { type: db.sql.Int, value: parseInt(idEmpresa) }
                }
            );
            if (filas === 0) {
                return res.status(404).json({ ok: false, mensaje: 'Cliente no encontrado' });
            }
            res.json({ ok: true, mensaje: 'Cliente eliminado permanentemente' });
        }
    } catch (error) {
        console.error('[CLIENTES] Error al eliminar:', error.message);
        res.status(500).json({ ok: false, mensaje: 'Error al eliminar cliente' });
    }
});

module.exports = router;
