import { Router, Request, Response } from 'express';
import PsWorkflowData from '../modelos-web/ps_workflow_data.modelo';
import { sequelize } from '../config/database';
import { QueryTypes } from 'sequelize';
import { verificaToken } from '../middlewares/autenticacion';
import { v4 as uuidv4 } from 'uuid';


const psWorkflowDataRouter = Router();

// Obtener todos los registros de ps_workflow_data
psWorkflowDataRouter.get('/', async (req: Request, res: Response) => {
  try {
    const data = await PsWorkflowData.findAll();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: 'Error al obtener los datos del flujo de trabajo' });
  }
});

psWorkflowDataRouter.get('/parte_trabajo', async (req: Request, res: Response) => {
  const { reference, id_order_detail } = req.query;

  if (!reference || !id_order_detail) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    // Consulta optimizada con JOINs directos y la tabla historial_casillero
    const workflowData = await sequelize.query(
      `
      SELECT 
        wd.*, 
        wt.id                   AS id_workflow_tarea, 
        wt.tarea_nombre, 
        wt.id_maquina, 
        wt.id_tarea, 
        et.nombre               AS estado_nombre, 
        op.nombre               AS operario_nombre, 
        m.nombre                AS maquina_nombre, 
        t.orden                 AS orden_tarea,
        wt.fecha_realizacion, 
        wt.estado               AS estado,
        CAST(
          CONCAT_WS(
            '/',
            ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
            COUNT(*)     OVER (PARTITION BY wd.id_order)
          ) AS CHAR
        )                       AS numero_trabajo,
        pwf.thumnailurl         AS imagen,
        hc.id_casillero         AS casillero_nombre,
        t.id_tipo_tarea         AS id_tipo_tarea,
        wd.fecha_entrega        AS fecha_entrega,
        ped2.nombre_seleccion   AS caracteristicas_impresion,
        wt.product_quantity     AS cantidad_articulos
      FROM ps_workflow_data wd
      JOIN ps_workflow_tareas wt 
        ON wd.id_order_detail = wt.id_order_detail 
        AND wd.id_order        = wt.id_order 
        AND wd.id_value        = wt.id_value
      LEFT JOIN estado_trabajo et 
        ON wt.estado = et.id
      LEFT JOIN operario op 
        ON wt.id_operario = op.id
      LEFT JOIN maquina m 
        ON wt.id_maquina = m.id
      LEFT JOIN ps_workflow_files pwf
        ON wd.id_order        = pwf.id_order
        AND wd.id_order_detail = pwf.id_order_detail
        AND wd.id_plugins      = pwf.id_plugins
      LEFT JOIN historial_casillero hc
        ON hc.id_tarea = wt.id
      LEFT JOIN casillero cas
        ON hc.id_casillero = cas.nombre
      LEFT JOIN tarea t 
        ON wt.id_tarea = t.id
      LEFT JOIN ps_workflow_data ped2
        ON ped2.reference            = wd.reference
        AND ped2.id_order_detail      = wd.id_order_detail
        AND ped2.nombre_campo_plugin  = 'Control ficheros'
      WHERE wd.reference        = :reference 
        AND wd.id_order_detail  = :id_order_detail
        AND wd.current_state    = 3
        AND wt.id_tarea IS NOT NULL
      ORDER BY wt.fecha_realizacion IS NULL, wt.fecha_realizacion ASC,  t.orden ASC
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { reference, id_order_detail },
      }
    );

    if (!workflowData || workflowData.length === 0) {
      return res.status(404).json({ error: 'No se encontraron registros en ps_workflow_data con los parámetros proporcionados' });
    }

    // Determinar la tarea actual (la primera que no está en estado 4)
    const tareaActual = workflowData.find((t: any) => t.estado !== 4) || null;

    const imagen: any = (tareaActual as any)?.imagen ?? 'Imagen no cargada';

    // Devolver la respuesta final
    res.json({
      imagenes: imagen,
      tareas: workflowData,
      tarea_actual: tareaActual,
    });
  } catch (error) {
    console.error('Error al obtener los registros combinados:', error);
    res.status(500).json({ error: 'Error al obtener los registros combinados' });
  }
});

psWorkflowDataRouter.get('/caracteristicas', async (req: Request, res: Response) => {
    const { reference, id_order_detail } = req.query;

    // 1. Validación de parámetros
    if (!reference || !id_order_detail) {
      return res
        .status(400)
        .json({ error: 'Faltan parámetros reference o id_order_detail' });
    }

    try {
      // 2. Pivot SQL para extraer cada valor en su propia columna
      const [row]: any[] = await sequelize.query(
        `
        SELECT
          MAX(CASE WHEN nombre_campo_plugin = 'Ubicación Vaina'     THEN nombre_seleccion END) AS posicion_vainas,
          MAX(CASE WHEN nombre_campo_plugin = 'Diametro Tubo o Cable' THEN nombre_seleccion END) AS diametro_tubo_cable,
          MAX(CASE WHEN nombre_campo_plugin = 'Refuerzo Perimetral'   THEN nombre_seleccion END) AS refuerzos,
          MAX(CASE WHEN nombre_campo_plugin = 'Tipo de Corte'         THEN nombre_seleccion END) AS tipo_corte,
          MAX(CASE WHEN titulo_publico         = 'Velcro'             THEN nombre_seleccion END) AS velcro,
          MAX(CASE WHEN nombre_grupo           = 'Revisión profesional' THEN nombre_seleccion END) AS revision_profesional,
          MAX(CASE WHEN nombre_campo_plugin = 'Referencia Producto'   THEN value            END) AS ref_producto,
          MAX(CASE WHEN nombre_campo_plugin = 'Control ficheros'      THEN nombre_seleccion END) AS control_ficheros,
          MAX(fecha_entrega) AS entrega_estimada
        FROM ps_workflow_data
        WHERE reference = :reference
          AND id_order_detail = :id_order_detail
        `,
        {
          replacements: { reference, id_order_detail },
          type: QueryTypes.SELECT,
        }
      );

      // 3. ¿Hay datos?
      if (!row || Object.values(row).every((v) => v == null)) {
        return res
          .status(404)
          .json({
            error:
              'No se encontró ningún registro en ps_workflow_data para esos parámetros',
          });
      }

      // 4. Devolver el objeto con tus campos
      return res.json({
        posicion_vainas:       row.posicion_vainas,
        diametro_tubo_cable:   row.diametro_tubo_cable,
        refuerzos:             row.refuerzos,
        tipo_corte:            row.tipo_corte,
        velcro:                row.velcro,
        revision_profesional:  row.revision_profesional,
        ref_producto:          row.ref_producto,
        control_ficheros:      row.control_ficheros,
        entrega_estimada:      row.entrega_estimada,
      });
    } catch (error) {
      console.error('Error al obtener características:', error);
      return res
        .status(500)
        .json({ error: 'Error interno al recuperar las características' });
    }
  }
);

psWorkflowDataRouter.get('/parte_trabajo_excluye_tarea_actual', async (req: Request, res: Response) => {
  const { id_order, id_order_detail } = req.query;

  if (!id_order || !id_order_detail) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    const registros = await sequelize.query(
      `
        WITH tarea_actual AS ( SELECT wt.id AS id_workflow_tarea, t.orden AS orden_tarea
          FROM ps_workflow_tareas wt
          JOIN tarea t ON wt.id_tarea = t.id
          WHERE wt.id_order = :id_order
            AND wt.id_order_detail = :id_order_detail
            AND wt.estado <> 4
          ORDER BY orden_tarea LIMIT 1)
        SELECT 
          wd.*, 
          wt.id AS id_workflow_tarea, 
          wt.tarea_nombre, 
          wt.id_maquina, 
          wt.id_tarea, 
          et.nombre AS estado_nombre, 
          op.nombre AS operario_nombre, 
          m.nombre AS maquina_nombre, 
          c.nombre AS casillero_nombre, 
          t.orden AS orden_tarea,
          wt.fecha_realizacion, 
          wt.estado AS estado,
          CAST(
          CONCAT_WS(
            '/',
            ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
            COUNT(*)     OVER (PARTITION BY wd.id_order)
          )
          AS CHAR
        ) AS numero_trabajo
        FROM ps_workflow_data wd
        JOIN ps_workflow_tareas wt 
          ON wd.id_order_detail = wt.id_order_detail 
        AND wd.id_order = wt.id_order 
        AND wd.id_value = wt.id_value
        LEFT JOIN estado_trabajo et ON wt.estado = et.id
        LEFT JOIN operario op ON wt.id_operario = op.id
        LEFT JOIN maquina m ON wt.id_maquina = m.id
        LEFT JOIN casillero c 
          ON c.pedido = CASE 
              WHEN EXISTS (
                SELECT 1 
                FROM casillero c1 
                WHERE c1.pedido = CONCAT(wd.reference, '-', wd.id_order_detail)
              )
              THEN CONCAT(wd.reference, '-', wd.id_order_detail)
              WHEN wt.grupo_trabajo IS NOT NULL 
              THEN CONCAT(wd.reference, '-', wt.grupo_trabajo)
              ELSE NULL
            END
        LEFT JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.id_order = :id_order 
          AND wt.id_order_detail = :id_order_detail
          -- AND wd.current_state IN (3, 33)
          AND wd.current_state = 3
          AND wt.id NOT IN (SELECT id_workflow_tarea FROM tarea_actual)
        ORDER BY t.orden ASC
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_order: id_order, id_order_detail: id_order_detail },
      }
    );

    if (!registros || registros.length === 0) {
      return res.status(404).json({ error: 'No se encontraron registros con los parámetros proporcionados' });
    }

    res.json(registros);
  } catch (error) {
    console.error('Error al obtener los registros:', error);
    res.status(500).json({ error: 'Error al obtener los registros' });
  }
});

psWorkflowDataRouter.get('/parte_trabajo_tarea_actual', async (req: Request, res: Response) => {
  const { id_order, id_order_detail } = req.query;

  if (!id_order || !id_order_detail) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    const [workflowData]: any = await sequelize.query(
      `
        SELECT wt.id AS id_workflow_tarea, wt.id_tarea, wt.id_maquina, wd.reference AS reference, wt.product_quantity AS product_quantity, wd.fecha_entrega AS fecha_entrega, wt.tarea_nombre AS tarea_nombre
        FROM ps_workflow_tareas wt
        JOIN tarea t ON t.id = wt.id_tarea
        JOIN ps_workflow_data wd ON wt.id_order = wd.id_order AND wt.id_order_detail = wd.id_order_detail AND wt.id_value = wd.id_value
        WHERE wt.id_order = :id_order AND wt.id_order_detail = :id_order_detail
        AND (wt.estado = 1 OR wt.estado = 3)  
        ORDER BY t.orden
        LIMIT 1;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_order, id_order_detail },
      }
    );

    if (!workflowData) {
      return res.status(404).json({ error: 'No se encontró la tarea actual pendiente para realizar' });
    }

    res.json(workflowData);
  } catch (error) {
    console.error('Error al obtener la tarea actual:', error);
    res.status(500).json({ error: 'Error al obtener la tarea actual' });
  }
});

psWorkflowDataRouter.get('/parte_trabajo_tareas_siguientes', async (req: Request, res: Response) => {
  const { reference, id_order_detail } = req.query;

  if (!reference || !id_order_detail) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    // Consulta optimizada con JOINs directos
    const workflowData = await sequelize.query(
      `
      SELECT wd.*, wt.tarea_nombre, wt.id_maquina, wt.id_tarea, 
             et.nombre AS estado_nombre, op.nombre AS operario_nombre, 
             m.nombre AS maquina_nombre, t.orden AS orden_tarea
      FROM ps_workflow_data wd
      LEFT JOIN ps_workflow_tareas wt 
        ON wd.id_order_detail = wt.id_order_detail 
        AND wd.id_order = wt.id_order 
        AND wd.id_value = wt.id_value
      LEFT JOIN estado_trabajo et 
        ON wd.current_state = et.id
      LEFT JOIN operario op 
        ON wd.id_operario = op.id
      LEFT JOIN maquina m 
        ON wt.id_maquina = m.id
      LEFT JOIN tarea t 
        ON wt.id_tarea = t.id
      WHERE wd.reference = :reference 
      AND wd.id_order_detail = :id_order_detail
      ORDER BY t.orden ASC
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { reference, id_order_detail },
      }
    );

    if (!workflowData || workflowData.length === 0) {
      return res.status(404).json({ error: 'No se encontraron registros en ps_workflow_data con los parámetros proporcionados' });
    }

    res.json(workflowData);
  } catch (error) {
    console.error('Error al obtener los registros:', error);
    res.status(500).json({ error: 'Error al obtener los registros' });
  }
});

psWorkflowDataRouter.get('/parte_trabajo_tareas_anteriores', async (req: Request, res: Response) => {
  const { id_order, id_order_detail } = req.query;

  if (!id_order || !id_order_detail) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    // Obtener la orden de la tarea actual pendiente
    const [tareaActual]: any = await sequelize.query(
      `
      SELECT t.orden AS orden_tarea
      FROM ps_workflow_tareas wt
      JOIN tarea t ON wt.id_tarea = t.id
      WHERE wt.id_order = :id_order
        AND wt.id_order_detail = :id_order_detail
        AND wt.estado <> 4
      ORDER BY t.orden ASC
      LIMIT 1
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_order, id_order_detail },
      }
    );

    if (!tareaActual) {
      return res.status(404).json({ error: 'No se encontró la tarea actual' });
    }

    // Agrupar tareas anteriores por tipo de tarea (id_tarea)
    // Obtener solo la tarea original de cada tipo
      const tareasAnteriores = await sequelize.query(
        `
        SELECT 
          wt.id AS id_workflow_tarea,
          wt.id_tarea,
          t.nombre AS tarea_nombre,
          t.orden AS orden_tarea,
          wt.product_quantity AS unidades_tarea
        FROM ps_workflow_tareas wt
        JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.id_order = :id_order 
          AND wt.id_order_detail = :id_order_detail
          AND t.orden < :ordenActual
          AND wt.id IN (
            SELECT MIN(wt2.id)
            FROM ps_workflow_tareas wt2
            WHERE wt2.id_order = :id_order
              AND wt2.id_order_detail = :id_order_detail
            GROUP BY wt2.id_tarea
          )
        ORDER BY t.orden ASC
        `,    
      {
        type: QueryTypes.SELECT,
        replacements: {
          id_order,
          id_order_detail,
          ordenActual: tareaActual.orden_tarea,
        },
      }
    );

    res.json(tareasAnteriores);
  } catch (error) {
    console.error('Error al obtener las tareas anteriores:', error);
    res.status(500).json({ error: 'Error al obtener las tareas anteriores' });
  }
});

psWorkflowDataRouter.post('/duplicar_tareas_anteriores', async (req: Request, res: Response) => {
  const { id_trabajo, id_order, id_order_detail } = req.body;

  if (!id_order || !id_order_detail || !id_trabajo) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    // Obtener el orden de la tarea actual
    const [tareaActual]: any = await sequelize.query(
      `
      SELECT wt.id_tarea, wt.orden
      FROM ps_workflow_tareas wt
      JOIN ps_workflow_data wd 
      ON wt.id_order = wd.id_order 
      AND wt.id_order_detail = wd.id_order_detail 
      AND wt.id_value = wd.id_value 
      WHERE wt.id = :id_trabajo
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_trabajo },
      }
    );
    
    if (!tareaActual) {
      return res.status(404).json({ error: 'No se encontró la tarea actual.' });
    }
    console.log('tareaActual', tareaActual);

    const ordenTareaActual = tareaActual.orden;

    // Actualizar la tarea anterior (poner estado = 5)
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET estado = 5
      WHERE wt.id = :id_trabajo
      `,
      {
        type: QueryTypes.UPDATE,
        replacements: {
          id_trabajo
        },
      }
    );

    // Obtener las tareas anteriores para duplicarlas
    const tareasAnteriores = await sequelize.query(
      `
      SELECT 
        wt.*, 
        t.orden, 
        t.nombre AS tarea_nombre
      FROM ps_workflow_tareas wt
      JOIN tarea t ON wt.id_tarea = t.id
      WHERE wt.id_order_detail = :id_order_detail
        AND wt.id_order = :id_order
        AND t.orden < :ordenTareaActual
      ORDER BY t.orden ASC
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_order, id_order_detail, ordenTareaActual },
      }
    );

    if (!tareasAnteriores || tareasAnteriores.length === 0) {
      return res.status(404).json({ error: 'No se encontraron tareas anteriores para duplicar.' });
    }

    // Clonar todas las columnas dinámicamente para las nuevas tareas
    const nuevasTareas = tareasAnteriores.map((tarea: any) => {
      const nuevaTarea = { ...tarea };
      delete nuevaTarea.id;
      nuevaTarea.id_operario = null;
      nuevaTarea.estado = 1; // Estado para la nueva tarea (pendiente, por ejemplo)
      nuevaTarea.fecha_realizacion = null; // Nueva tarea no realizada
      return nuevaTarea;
    });

    // Inserción de nuevas tareas en la base de datos (ps_workflow_tareas)
    await sequelize.getQueryInterface().bulkInsert('ps_workflow_tareas', nuevasTareas);

    // Obtener los IDs de las tareas duplicadas
    const tareasDuplicadasIds = await sequelize.query(
      `
      SELECT id
      FROM ps_workflow_tareas
      WHERE id_order = :id_order
        AND id_order_detail = :id_order_detail
        AND id_tarea IN (:id_tareas)
      `,
      {
        type: QueryTypes.SELECT,
        replacements: {
          id_order,
          id_order_detail,
          id_tareas: nuevasTareas.map((tarea) => tarea.id_tarea), // IDs de las tareas originales
        },
      }
    );

    // Devolver la respuesta con los nuevos IDs de las tareas duplicadas
    if (tareasDuplicadasIds && tareasDuplicadasIds.length > 0) {
      console.log('tareasDuplicadasIds', tareasDuplicadasIds);
      res.status(201).json({
        message: 'Tareas duplicadas correctamente',
        tareasDuplicadas: tareasDuplicadasIds,
      });
    } else {
      res.status(404).json({ error: 'No se pudieron obtener los IDs de las nuevas tareas duplicadas' });
    }
  } catch (error) {
    console.error('Error al duplicar las tareas anteriores:', error);
    res.status(500).json({ error: 'Error al duplicar las tareas anteriores' });
  }
});

// Endpoint 1: duplicar_con_actualizacion
psWorkflowDataRouter.post('/duplicar_con_actualizacion', async (req, res) => {
  const { id_trabajo_original, unidades_nueva_tarea, idOperario } = req.body;

  const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');
  const grupo_trabajo = uuidv4();

  if (!id_trabajo_original || unidades_nueva_tarea == null) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud.' });
  }

  try {
    const trabajoOriginal: any = await sequelize.query(`
      SELECT wt.*, wd.product_nombre
      FROM ps_workflow_tareas wt
      JOIN ps_workflow_data wd 
        ON wt.id_order = wd.id_order
        AND wt.id_order_detail = wd.id_order_detail
        AND wt.id_value = wd.id_value
      WHERE wt.id = :id_trabajo_original
    `, {
      replacements: { id_trabajo_original },
      type: QueryTypes.SELECT,
    }).then(r => r[0]);

    if (!trabajoOriginal) {
      return res.status(404).json({ error: 'Trabajo original no encontrado.' });
    }

    if (unidades_nueva_tarea > trabajoOriginal.product_quantity) {
      return res.status(400).json({
        error: 'Las unidades de la nueva tarea no pueden ser mayores a las del trabajo original.',
      });
    }

    const { id_order, id_order_detail } = trabajoOriginal;

    const filaOrdenSeleccionada: any = await sequelize.query(`
      SELECT t.orden, wt.id_tarea
      FROM ps_workflow_tareas wt
      JOIN tarea t ON wt.id_tarea = t.id
      WHERE wt.id = :id_trabajo_original
    `, {
      replacements: { id_trabajo_original },
      type: QueryTypes.SELECT,
    }).then(r => r[0]);

    if (!filaOrdenSeleccionada) {
      return res.status(404).json({ error: 'No se encontró el orden de la tarea seleccionada.' });
    }

    const ordenSeleccionada = filaOrdenSeleccionada.orden;
    const idTareaSeleccionada = filaOrdenSeleccionada.id_tarea;

    const tareaPendiente: any = await sequelize.query(`
      SELECT t.orden, wt.id AS id_workflow_tarea
      FROM ps_workflow_tareas wt
      JOIN tarea t ON wt.id_tarea = t.id
      WHERE wt.id_order = :id_order
        AND wt.id_order_detail = :id_order_detail
        AND wt.estado <> 4
      ORDER BY t.orden ASC
      LIMIT 1
    `, {
      replacements: { id_order, id_order_detail },
      type: QueryTypes.SELECT,
    }).then(r => r[0]);

    if (!tareaPendiente) {
      return res.status(404).json({ error: 'No hay tarea actual pendiente para duplicar.' });
    }

    const ordenActual = tareaPendiente.orden;
    const id_tarea_actual = tareaPendiente.id_workflow_tarea;
    const unidadesTareaActual = trabajoOriginal.product_quantity - unidades_nueva_tarea;

    await sequelize.query(`
      UPDATE ps_workflow_tareas
      SET estado = 5, fecha_realizacion = :fecha, id_operario = :idOperario, product_quantity = :unidadesTareaActual
      WHERE id = :id_tarea_actual
    `, {
      replacements: { id_tarea_actual, fecha, idOperario, unidadesTareaActual },
      type: QueryTypes.UPDATE,
    });

    const tareasADuplicar = await sequelize.query(`
      WITH TareasOriginales AS (
        SELECT wt.*, ROW_NUMBER() OVER (PARTITION BY wt.id_tarea, wt.id_maquina ORDER BY wt.id ASC) AS rn
        FROM ps_workflow_tareas wt
        JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.id_order = :id_order
          AND wt.id_order_detail = :id_order_detail
          AND t.orden BETWEEN :ordenSeleccionada AND :ordenActual
      )
      SELECT * FROM TareasOriginales WHERE rn = 1
      ORDER BY orden ASC;
    `, {
      replacements: { id_order, id_order_detail, ordenSeleccionada, ordenActual },
      type: QueryTypes.SELECT,
    });

    if (!tareasADuplicar.length) {
      return res.status(404).json({ error: 'No se encontraron tareas a duplicar.' });
    }

    const nuevasTareas = tareasADuplicar.map((tarea, idx, array) => {
      const nueva: any = { ...tarea };
      delete nueva.id;
      delete nueva.rn;
      nueva.id_operario = null;
      nueva.estado = 1;
      nueva.fecha_realizacion = null;
      nueva.grupo_trabajo = grupo_trabajo;
      // nueva.product_quantity = (idx === array.length - 1)
      //   ? trabajoOriginal.product_quantity
      //   : unidades_nueva_tarea;
      nueva.product_quantity = unidades_nueva_tarea;
      return nueva;
    });

    await sequelize.getQueryInterface().bulkInsert('ps_workflow_tareas', nuevasTareas);

    const tareasDuplicadas = await sequelize.query(`
      SELECT id, id_tarea
      FROM ps_workflow_tareas
      WHERE grupo_trabajo = :grupo_trabajo
    `, {
      replacements: { grupo_trabajo },
      type: QueryTypes.SELECT,
    });

    await sequelize.query(`
      UPDATE ps_workflow_tareas
      SET grupo_trabajo = NULL
      WHERE grupo_trabajo = :grupo_trabajo
    `, {
      replacements: { grupo_trabajo },
      type: QueryTypes.UPDATE,
    });

    const tareaEnvio: any = tareasDuplicadas.find((t: any) => t.id_tarea === idTareaSeleccionada);

    if (!tareaEnvio) {
      return res.status(404).json({ error: 'No se encontró la tarea de envío en las duplicadas.' });
    }

    return res.status(201).json({
      message: 'Tareas duplicadas correctamente.',
      nuevaTarea: { id: tareaEnvio.id },
      tareasDuplicadas: tareasDuplicadas.map((t: any) => t.id),
    });
  } catch (error) {
    console.error('Error en duplicar_con_actualizacion:', error);
    return res.status(500).json({ error: 'Error al duplicar y actualizar el trabajo.' });
  }
});


// Endpoint 2: duplicar_tareas_desde_seleccion
psWorkflowDataRouter.post('/duplicar_tareas_desde_seleccion', async (req, res) => {
  const { id_seleccionada, id_order, id_order_detail, idOperario } = req.body;
  const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');
  const grupo_trabajo = uuidv4();

  if (!id_seleccionada || !id_order || !id_order_detail || !idOperario) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    const [tareaSeleccionada]: any = await sequelize.query(`
      SELECT t.orden
      FROM ps_workflow_tareas wt
      JOIN tarea t ON wt.id_tarea = t.id
      WHERE wt.id = :id_seleccionada
    `, {
      replacements: { id_seleccionada },
      type: QueryTypes.SELECT,
    });

    if (!tareaSeleccionada) {
      return res.status(404).json({ error: 'Tarea seleccionada no encontrada.' });
    }

    const ordenSeleccionada = tareaSeleccionada.orden;

    const [tareaActual]: any = await sequelize.query(`
      SELECT t.orden, wt.id AS id_workflow_tarea
      FROM ps_workflow_tareas wt
      JOIN tarea t ON wt.id_tarea = t.id
      WHERE wt.id_order = :id_order
        AND wt.id_order_detail = :id_order_detail
        AND wt.estado <> 4
      ORDER BY t.orden ASC
      LIMIT 1
    `, {
      replacements: { id_order, id_order_detail },
      type: QueryTypes.SELECT,
    });

    if (!tareaActual) {
      return res.status(404).json({ error: 'No hay tarea actual pendiente para duplicar.' });
    }

    const ordenActual = tareaActual.orden;
    const id_tarea_actual = tareaActual.id_workflow_tarea;

    await sequelize.query(`
      UPDATE ps_workflow_tareas
      SET estado = 5, fecha_realizacion = :fecha, id_operario = :idOperario
      WHERE id = :id_tarea_actual
    `, {
      replacements: { id_tarea_actual, fecha, idOperario },
      type: QueryTypes.UPDATE,
    });

    const tareasARedupl = await sequelize.query(`
      WITH TareasOriginales AS (
        SELECT wt.*, ROW_NUMBER() OVER (PARTITION BY wt.id_tarea, wt.id_maquina ORDER BY wt.id ASC) AS rn
        FROM ps_workflow_tareas wt
        JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.id_order = :id_order
          AND wt.id_order_detail = :id_order_detail
          AND t.orden BETWEEN :ordenSeleccionada AND :ordenActual
      )
      SELECT * FROM TareasOriginales WHERE rn = 1
      ORDER BY orden ASC;
    `, {
      replacements: { id_order, id_order_detail, ordenSeleccionada, ordenActual },
      type: QueryTypes.SELECT,
    });

    if (!tareasARedupl.length) {
      return res.status(404).json({ error: 'No se encontraron tareas para duplicar.' });
    }

    const nuevasTareas = tareasARedupl.map((t: any) => {
      const nueva = { ...t };
      delete nueva.id;
      delete nueva.rn;
      nueva.estado = 1;
      nueva.fecha_realizacion = null;
      nueva.grupo_trabajo = grupo_trabajo;
      return nueva;
    });

    await sequelize.getQueryInterface().bulkInsert('ps_workflow_tareas', nuevasTareas);

    const tareasDuplicadasIds = await sequelize.query(`
      SELECT id, id_tarea, id_maquina
      FROM ps_workflow_tareas
      WHERE grupo_trabajo = :grupo_trabajo
    `, {
      replacements: { grupo_trabajo },
      type: QueryTypes.SELECT,
    });

    await sequelize.query(`
      UPDATE ps_workflow_tareas
      SET grupo_trabajo = NULL
      WHERE grupo_trabajo = :grupo_trabajo
    `, {
      replacements: { grupo_trabajo },
      type: QueryTypes.UPDATE,
    });
    return res.status(201).json({
      message: 'Tareas duplicadas correctamente (agrupadas por tipo).',
      tareasDuplicadas: tareasDuplicadasIds,
    });
  } catch (err) {
    console.error('Error al duplicar tareas desde seleccion:', err);
    return res.status(500).json({ error: 'Error al duplicar tareas desde seleccion.' });
  }
});

psWorkflowDataRouter.get('/maquinas_con_trabajos', async (req: Request, res: Response) => {
  const { id_tipomaquina } = req.query;

  if (!id_tipomaquina) {
    return res.status(400).json({ error: 'El parámetro id_tipomaquina es obligatorio' });
  }

  try {

    // **1️⃣ Asegurar que las columnas necesarias existan en `ps_workflow_tareas`**
    const checkColumns = await sequelize.query(
      `SELECT COLUMN_NAME 
       FROM INFORMATION_SCHEMA.COLUMNS 
       WHERE TABLE_NAME = 'ps_workflow_tareas' 
       AND COLUMN_NAME IN ('estado', 'id_operario', 'fecha_realizacion', 'grupo_trabajo');`,
      { type: QueryTypes.SELECT }
    );
    
    const existingColumns = checkColumns.map((col: any) => col.COLUMN_NAME);
    
    // Si no existen todas las columnas, entonces ejecutamos ALTER TABLE
    if (!existingColumns.includes('estado') || 
        !existingColumns.includes('id_operario') || 
        !existingColumns.includes('fecha_realizacion')||
        !existingColumns.includes('grupo_trabajo')) {
      
      await sequelize.query(
        `ALTER TABLE ps_workflow_tareas 
         ADD COLUMN IF NOT EXISTS estado INT DEFAULT 1,
         ADD COLUMN IF NOT EXISTS id_operario INT NULL,
         ADD COLUMN IF NOT EXISTS fecha_realizacion DATETIME NULL,
         ADD COLUMN IF NOT EXISTS grupo_trabajo INT NULL;`,
        { type: QueryTypes.RAW }
      );
    }   

    // 1️⃣ Obtener los trabajos y materiales asociados
    const maquinasConTrabajos = await sequelize.query(
      `
      WITH MaterialPrioritario AS (
        SELECT
          id_value,
          id_material,
          PRIORIDAD,
          ROW_NUMBER() OVER (PARTITION BY id_value ORDER BY prioridad ASC) AS rn
        FROM ps_workflow_material
      ),
      TareasPendientes AS (
        SELECT 
          wt.id AS trabajo_id,
          wt.id_order,
          wt.id_order_detail,
          wt.id_value,
          wd.reference,
          wd.product_nombre,
          wt.product_quantity,
          wd.fecha_entrega,
          wt.estado,
          t.orden AS orden_tarea,
          t.nombre AS nombre_tarea,
          wt.id_tarea,
          wt.id_maquina AS id_maquina,
          m.nombre AS maquina_nombre,
          m.perfiles_color,
          mat.id AS id_material,
          mat.nombre AS material_nombre,
          wt.grupo_trabajo,
          wdm.ancho,
          wdm.alto,
          CAST(
            CONCAT_WS(
              '/',
              ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
              COUNT(*) OVER (PARTITION BY wd.id_order)
            ) AS CHAR
          ) AS numero_trabajo
        FROM ps_workflow_tareas wt
        JOIN ps_workflow_data wd 
          ON wt.id_order = wd.id_order 
        AND wt.id_order_detail = wd.id_order_detail 
        AND wt.id_value = wd.id_value
        JOIN ps_workflow_data_medidas wdm 
          ON wdm.id_order_detail = wd.id_order_detail 
        AND wdm.id_plugins = wd.id_plugins
        JOIN tarea t 
          ON wt.id_tarea = t.id
        JOIN maquina m 
          ON wt.id_maquina = m.id
        LEFT JOIN MaterialPrioritario mp
          ON wd.id_value = mp.id_value
        AND mp.rn = 1
        LEFT JOIN material mat 
          ON mp.id_material = mat.id
        WHERE m.id_tipomaquina = :id_tipomaquina
          AND wd.current_state = 3
          AND wt.estado NOT IN (4, 5)
      ),
      -- ✅ Tareas anteriores que aún tienen unidades sin completar
      TareasAnterioresPendientes AS (
        SELECT
          wt.id_order_detail,
          t.orden,
          COUNT(*) AS unidades_pendientes
        FROM ps_workflow_tareas wt
        JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.estado NOT IN (4, 5)
        GROUP BY wt.id_order_detail, t.orden
      ),
      -- ✅ Solo las tareas disponibles (sin tareas anteriores pendientes)
      TareasDisponibles AS (
        SELECT
          tp.*
        FROM TareasPendientes tp
        LEFT JOIN TareasAnterioresPendientes tap
          ON tp.id_order_detail = tap.id_order_detail
        AND tap.orden < tp.orden_tarea
        WHERE tap.id_order_detail IS NULL -- No hay tareas anteriores incompletas
      )
      SELECT
        td.*,
        (
          SELECT wt2.id_maquina
          FROM ps_workflow_tareas wt2
          JOIN tarea t2 
            ON wt2.id_tarea = t2.id
          WHERE wt2.id_order = td.id_order
            AND wt2.id_order_detail = td.id_order_detail
            AND t2.orden > td.orden_tarea
            AND wt2.estado <> 4
          ORDER BY t2.orden ASC
          LIMIT 1
        ) AS next_machine_id,
        ped.nombre_seleccion AS plazo_entrega,
        ped2.nombre_seleccion AS carac_impresion
      FROM TareasDisponibles td
      LEFT JOIN ps_workflow_data ped
        ON ped.reference = td.reference
      AND ped.id_order_detail = td.id_order_detail
      AND ped.nombre_campo_plugin = 'Plazo de Entrega'
      LEFT JOIN ps_workflow_data ped2
        ON ped2.reference = td.reference
      AND ped2.id_order_detail = td.id_order_detail
      AND ped2.nombre_campo_plugin = 'Control ficheros'
      ORDER BY
        DATE(td.fecha_entrega) ASC,
        FIELD(ped.nombre_seleccion,
              'Expréss',
              'Estándar',
              'SemiRelax',
              'Relax'),
        td.reference ASC;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_tipomaquina },
      }
    );

    if (!maquinasConTrabajos.length) {
      return res.json({ totalTrabajos: 0, maquinasConTrabajos: [] });
    }

    // 2️⃣ **Agrupar los datos en la estructura esperada por el HTML**
    const maquinasMap: Record<string, any> = {};
    let totalTrabajos = 0;

    maquinasConTrabajos.forEach((trabajo: any) => {
      const maquinaId = trabajo.id_maquina;
      const pedidoId = trabajo.reference;
      const materialNombre = trabajo.material_nombre || 'Sin material'; // Asegurar que siempre hay un valor
      const grupoTrabajo = trabajo.grupo_trabajo || '-';

      // **1️⃣ Agrupar por máquina**
      if (!maquinasMap[maquinaId]) {
        maquinasMap[maquinaId] = {
          maquina_id: maquinaId,
          maquina_nombre: trabajo.maquina_nombre || '-',
          trabajosPendientes: 0,
          materiales: {},
        };
      }

      // **2️⃣ Agrupar por material**
      if (!maquinasMap[maquinaId].materiales[materialNombre]) {
        maquinasMap[maquinaId].materiales[materialNombre] = {
          material: materialNombre,
          agrupaciones: {},
        };
      }

      // **3️⃣ Agrupar por grupo de trabajo**
      if (!maquinasMap[maquinaId].materiales[materialNombre].agrupaciones[grupoTrabajo]) {
        maquinasMap[maquinaId].materiales[materialNombre].agrupaciones[grupoTrabajo] = {
          grupo_id: grupoTrabajo,
          pedidos: {},
        };
      }

      // **4️⃣ Agrupar por pedido**
      if (!maquinasMap[maquinaId].materiales[materialNombre].agrupaciones[grupoTrabajo].pedidos[pedidoId]) {
        maquinasMap[maquinaId].materiales[materialNombre].agrupaciones[grupoTrabajo].pedidos[pedidoId] = {
          pedido: pedidoId,
          trabajos: [],
        };
      }

      // **5️⃣ Añadir trabajo**
      maquinasMap[maquinaId].materiales[materialNombre].agrupaciones[grupoTrabajo].pedidos[pedidoId].trabajos.push({
        id: trabajo.trabajo_id,
        id_order_detail: trabajo.id_order_detail,
        id_order: trabajo.id_order,
        id_value: trabajo.id_value,
        numero_trabajo: trabajo.numero_trabajo,
        articulo: trabajo.product_nombre,
        unidades: trabajo.product_quantity,
        fechaEntrega: trabajo.fecha_entrega,
        estado: trabajo.estado,
        grupo_trabajo: grupoTrabajo,
        ancho: trabajo.ancho,
        alto: trabajo.alto,
        perfiles_color: trabajo.perfiles_color,
        material: trabajo.id_material,
        next_machine_id: trabajo.next_machine_id,
        carac_impresion: trabajo.carac_impresion,
        plazo_entrega: trabajo.plazo_entrega,
        id_tarea: trabajo.id_tarea
      });

      maquinasMap[maquinaId].trabajosPendientes++;
      totalTrabajos++;
    });

    // 3️⃣ **Formatear la respuesta final**
    const response = Object.values(maquinasMap).map((maquina: any) => ({
      maquina_id: maquina.maquina_id,
      maquina_nombre: maquina.maquina_nombre,
      trabajosPendientes: maquina.trabajosPendientes,
      materiales: Object.values(maquina.materiales).map((material: any) => ({
        material: material.material,
        agrupaciones: Object.values(material.agrupaciones).map((grupo: any) => ({
          grupo_id: grupo.grupo_id,
          pedidos: Object.values(grupo.pedidos),
        })),
      })),
    }));

    res.json({
      totalTrabajos,
      maquinasConTrabajos: response,
    });

  } catch (error) {
    console.error('Error al obtener las máquinas con trabajos:', error);
    res.status(500).json({ error: 'Error al obtener las máquinas con trabajos' });
  }
});

psWorkflowDataRouter.get('/trabajos_embalaje', async (req, res) => {
  const { idTipomaquina } = req.query;

  if (!idTipomaquina) {
    return res.status(400).json({ error: 'El parámetro idTipomaquina es obligatorio' });
  }

  try {
    const trabajos: any = await sequelize.query(
      `
      SELECT emb.*
      FROM ps_workflow_tareas emb
      JOIN tarea t_emb ON emb.id_tarea = t_emb.id
      JOIN maquina m_emb ON emb.id_maquina = m_emb.id
      WHERE emb.estado IN (1, 2, 3)
        AND m_emb.id_tipomaquina = :idTipomaquina
        AND NOT EXISTS (
          SELECT 1
          FROM ps_workflow_tareas t_anterior
          JOIN tarea tarea_ant ON t_anterior.id_tarea = tarea_ant.id
          WHERE t_anterior.id_order = emb.id_order
            AND t_anterior.id_order_detail = emb.id_order_detail
            AND tarea_ant.orden < t_emb.orden
            AND t_anterior.estado NOT IN (4, 5)
        )
        AND NOT EXISTS (
          SELECT 1
          FROM ps_workflow_tareas otro
          WHERE otro.id_order = emb.id_order
            AND EXISTS (
              SELECT 1
              FROM ps_workflow_tareas t_anterior
              JOIN tarea tarea_ant ON t_anterior.id_tarea = tarea_ant.id
              JOIN tarea tarea_emb ON emb.id_tarea = tarea_emb.id
              WHERE t_anterior.id_order = otro.id_order
                AND t_anterior.id_order_detail = otro.id_order_detail
                AND tarea_ant.orden < tarea_emb.orden
                AND t_anterior.estado NOT IN (4, 5)
            )
        );
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idTipomaquina }
      }
    );

    if (!trabajos.length) {
      return res.json({ totalTrabajos: 0, pedidosPendientes: [] });
    }

    const pedidosMap: any = {};
    let totalTrabajos = 0;

    for (const row of trabajos) {
      const detalle = await sequelize.query(
      `
      WITH detalles_unicos AS (
        SELECT DISTINCT wt.id_order, wt.id_order_detail, wt.id_value
        FROM ps_workflow_tareas wt
      ),
      numerados AS (
        SELECT 
          du.id_order,
          du.id_order_detail,
          wd.reference,
          wd.product_nombre,
          wd.fecha_entrega,
          wdm.ancho,
          wdm.alto,
          o.nombre AS operario,
          wi.siglas,
          c.nombre AS casillero,
          CAST(
            CONCAT_WS(
              '/',
              ROW_NUMBER() OVER (
                PARTITION BY du.id_order
                ORDER BY du.id_order_detail
              ),
              COUNT(*) OVER (
                PARTITION BY du.id_order
              )
            ) AS CHAR
          ) AS numero_trabajo
        FROM detalles_unicos du
        JOIN ps_workflow_data wd 
          ON du.id_order = wd.id_order 
          AND du.id_order_detail = wd.id_order_detail 
          AND du.id_value = wd.id_value
        JOIN ps_workflow_data_medidas wdm 
          ON wdm.id_order_detail = wd.id_order_detail 
          AND wdm.id_plugins = wd.id_plugins
        LEFT JOIN operario o ON o.id = :id_operario
        LEFT JOIN ps_workflow_iconos wi ON wi.id_value = wd.id_value
        LEFT JOIN casillero c 
          ON c.pedido = CASE 
            WHEN EXISTS (
              SELECT 1 FROM casillero c1 
              WHERE c1.pedido = CONCAT(wd.reference, '-', wd.id_order_detail)
            ) THEN CONCAT(wd.reference, '-', wd.id_order_detail)
            WHEN :grupo_trabajo IS NOT NULL THEN CONCAT(wd.reference, '-', :grupo_trabajo)
            ELSE NULL
          END
      )
      SELECT * FROM numerados
      WHERE id_order_detail = :id_order_detail
      LIMIT 1;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: {
          id_operario: row.id_operario,
          grupo_trabajo: row.grupo_trabajo,
          id_order: row.id_order,
          id_order_detail: row.id_order_detail
        }
      }
    );



      const d: any = detalle[0];
      if (!pedidosMap[d.reference]) {
        pedidosMap[d.reference] = {
          pedido: d.reference,
          fecha: d.fecha_entrega,
          operario: d.operario,
          trabajos: [],
          bultosAgrupados: [],
          selectedTrabajos: []
        };
      }
console.log('>> numero_trabajo:', d.numero_trabajo, 'para detalle', d.id_order_detail);

      pedidosMap[d.reference].trabajos.push({
        trabajo_id: row.id,
        id_order: row.id_order,
        id_order_detail: row.id_order_detail,
        articulo: row.id_order_detail + '-' + d.numero_trabajo,
        casillero: d.casillero || '-',
        caja: 'X',
        producto: d.product_nombre,
        caracteristicas: d.siglas || '-',
        unidades: row.product_quantity,
        unidadesDisponibles: row.product_quantity,
        ancho: d.ancho,
        alto: d.alto,
        estado: row.estado,
        id_operario: row.id_operario,
        id_value: row.id_value
      });

      totalTrabajos++;
    }

    res.json({
      totalTrabajos,
      pedidosPendientes: Object.values(pedidosMap)
    });
  } catch (error) {
    console.error('Error al obtener trabajos de embalaje:', error);
    res.status(500).json({ error: 'Error interno del servidor' });
  }
});


// Endpoint actualizado: trabajos_embalaje
// Endpoint: trabajos_embalaje - Solo pedidos con todos sus artículos listos para embalar
// psWorkflowDataRouter.get('/trabajos_embalaje', async (req: Request, res: Response) => {
//   const { idTipomaquina } = req.query;

//   if (!idTipomaquina) {
//     return res.status(400).json({ error: 'El parámetro id_tipomaquina es obligatorio' });
//   }

//   try {
//     const trabajos = await sequelize.query(
//       `
//       WITH MaterialPrioritario AS (
//         SELECT
//           id_value,
//           id_material,
//           PRIORIDAD,
//           ROW_NUMBER() OVER (PARTITION BY id_value ORDER BY prioridad ASC) AS rn
//         FROM ps_workflow_material
//       ),
//       TareasPendientes AS (
//         SELECT 
//           wt.id AS trabajo_id,
//           wt.id_order,
//           wt.id_order_detail,
//           wt.id_value,
//           wd.reference,
//           wd.product_nombre,
//           wt.product_quantity,
//           wd.fecha_entrega,
//           wt.estado,
//           t.orden AS orden_tarea,
//           t.nombre AS nombre_tarea,
//           wt.id_tarea,
//           wt.id_maquina AS id_maquina,
//           m.nombre AS maquina_nombre,
//           m.perfiles_color,
//           mat.id AS id_material,
//           mat.nombre AS material_nombre,
//           wt.grupo_trabajo,
//           wdm.ancho,
//           wdm.alto,
//           CAST(
//             CONCAT_WS(
//               '/',
//               ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
//               COUNT(*) OVER (PARTITION BY wd.id_order)
//             ) AS CHAR
//           ) AS numero_trabajo
//         FROM ps_workflow_tareas wt
//         JOIN ps_workflow_data wd 
//           ON wt.id_order = wd.id_order 
//           AND wt.id_order_detail = wd.id_order_detail 
//           AND wt.id_value = wd.id_value
//         JOIN ps_workflow_data_medidas wdm 
//           ON wdm.id_order_detail = wd.id_order_detail 
//           AND wdm.id_plugins = wd.id_plugins
//         JOIN tarea t ON wt.id_tarea = t.id
//         JOIN maquina m ON wt.id_maquina = m.id
//         LEFT JOIN MaterialPrioritario mp
//           ON wd.id_value = mp.id_value AND mp.rn = 1
//         LEFT JOIN material mat ON mp.id_material = mat.id
//         WHERE m.id_tipomaquina = :idTipomaquina
//           AND wd.current_state = 3
//           AND wt.estado NOT IN (4, 5)
//       ),
//       TareasAnterioresPendientes AS (
//         SELECT
//           wt.id_order_detail,
//           t.orden,
//           COUNT(*) AS unidades_pendientes
//         FROM ps_workflow_tareas wt
//         JOIN tarea t ON wt.id_tarea = t.id
//         WHERE wt.estado NOT IN (4, 5)
//         GROUP BY wt.id_order_detail, t.orden
//       ),
//       TareasDisponibles AS (
//         SELECT
//           tp.*
//         FROM TareasPendientes tp
//         LEFT JOIN TareasAnterioresPendientes tap
//           ON tp.id_order_detail = tap.id_order_detail
//           AND tap.orden < tp.orden_tarea
//         WHERE tap.id_order_detail IS NULL
//       ),
//       ValidacionPedidosCompletos AS (
//         SELECT
//           td.id_order
//         FROM TareasDisponibles td
//         GROUP BY td.id_order
//         HAVING COUNT(*) = (
//           SELECT COUNT(DISTINCT id_order_detail)
//           FROM ps_workflow_tareas wt2
//           JOIN maquina m2 ON wt2.id_maquina = m2.id
//           JOIN tarea t2 ON wt2.id_tarea = t2.id
//           WHERE wt2.id_order = td.id_order
//             AND m2.id_tipomaquina = :idTipomaquina
//             AND wt2.estado NOT IN (4, 5)
//             AND t2.nombre <> 'Embalar'
//         )
//       )
//       SELECT
//         td.*,
//         (
//           SELECT wt2.id_maquina
//           FROM ps_workflow_tareas wt2
//           JOIN tarea t2 ON wt2.id_tarea = t2.id
//           WHERE wt2.id_order = td.id_order
//             AND wt2.id_order_detail = td.id_order_detail
//             AND t2.orden > td.orden_tarea
//             AND wt2.estado <> 4
//           ORDER BY t2.orden ASC
//           LIMIT 1
//         ) AS next_machine_id,
//         ped.nombre_seleccion AS plazo_entrega,
//         ped2.nombre_seleccion AS carac_impresion
//       FROM TareasDisponibles td
//       INNER JOIN ValidacionPedidosCompletos vpc ON td.id_order = vpc.id_order
//       LEFT JOIN ps_workflow_data ped
//         ON ped.reference = td.reference
//         AND ped.id_order_detail = td.id_order_detail
//         AND ped.nombre_campo_plugin = 'Plazo de Entrega'
//       LEFT JOIN ps_workflow_data ped2
//         ON ped2.reference = td.reference
//         AND ped2.id_order_detail = td.id_order_detail
//         AND ped2.nombre_campo_plugin = 'Control ficheros'
//       ORDER BY
//         DATE(td.fecha_entrega) ASC,
//         FIELD(ped.nombre_seleccion, 'Expréss', 'Estándar', 'SemiRelax', 'Relax'),
//         td.reference ASC;
//       `,
//       {
//         type: QueryTypes.SELECT,
//         replacements: { idTipomaquina },
//       }
//     );

//     if (!trabajos.length) {
//       return res.json({ totalTrabajos: 0, pedidosPendientes: [] });
//     }

//     const pedidosMap: Record<string, any> = {};
//     let totalTrabajos = 0;

//     trabajos.forEach((row: any) => {
//       const referencia = row.reference;

//       if (!pedidosMap[referencia]) {
//         pedidosMap[referencia] = {
//           pedido: referencia,
//           fecha: row.fecha_entrega,
//           trabajos: [],
//           bultosAgrupados: [],
//           selectedTrabajos: []
//         };
//       }

//       pedidosMap[referencia].trabajos.push({
//         trabajo_id: row.trabajo_id,
//         id_order: row.id_order,
//         id_order_detail: row.id_order_detail,
//         articulo: row.id_order_detail + '-' + row.numero_trabajo,
//         casillero: null,
//         caja: 'X',
//         producto: row.product_nombre,
//         caracteristicas: '-',
//         unidades: row.product_quantity,
//         unidadesDisponibles: row.product_quantity,
//         ancho: row.ancho,
//         alto: row.alto,
//         estado: row.estado,
//         id_operario: row.id_operario,
//         id_value: row.id_value
//       });

//       totalTrabajos++;
//     });

//     res.json({
//       totalTrabajos,
//       pedidosPendientes: Object.values(pedidosMap)
//     });

//   } catch (error) {
//     console.error('Error al obtener las máquinas con trabajos:', error);
//     res.status(500).json({ error: 'Error al obtener las máquinas con trabajos' });
//   }
// });


psWorkflowDataRouter.get('/trabajos_pendientes', async (_req, res) => {
  const sql = `
    SELECT 
        wd.reference AS pedido,
        wt.id_order_detail AS articulo,
        wt.product_quantity AS unidades,
        wdm.ancho,
        wdm.alto,
        c.nombre AS casillero,
        t.nombre AS tarea_actual,
        CAST(
            CONCAT_WS(
              '/',
              ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
              COUNT(*) OVER (PARTITION BY wd.id_order)
            ) AS CHAR
          ) AS numero_trabajo
    FROM ps_workflow_tareas wt
    JOIN ps_workflow_data wd 
        ON wt.id_order = wd.id_order 
        AND wt.id_order_detail = wd.id_order_detail 
        AND wt.id_value = wd.id_value
    JOIN ps_workflow_data_medidas wdm 
        ON wdm.id_order_detail = wd.id_order_detail 
        AND wdm.id_plugins = wd.id_plugins
    JOIN tarea t ON wt.id_tarea = t.id
    LEFT JOIN casillero c 
          ON c.pedido = CASE 
              WHEN EXISTS (
                SELECT 1 
                FROM casillero c1 
                WHERE c1.pedido = CONCAT(wd.reference, '-', wd.id_order_detail)
              )
              THEN CONCAT(wd.reference, '-', wd.id_order_detail)
              WHEN wt.grupo_trabajo IS NOT NULL 
              THEN CONCAT(wd.reference, '-', wt.grupo_trabajo)
              ELSE NULL
            END
    WHERE wt.estado <> 4
      AND wt.id_tarea = (
        SELECT wt2.id_tarea
        FROM ps_workflow_tareas wt2
        JOIN tarea t2 ON wt2.id_tarea = t2.id
        WHERE wt2.id_order_detail = wt.id_order_detail
          AND wt2.estado <> 4
        ORDER BY t2.orden ASC
        LIMIT 1
      )
    ORDER BY DATE(wd.fecha_entrega) ASC;
  `;

  try {
    const result = await sequelize.query(sql, { type: QueryTypes.SELECT });
  
    const trabajosFormateados = (result as any[]).map(row => ({
      casillero: row.casillero || '-',
      pedido: row.pedido,
      articulo: row.articulo + '-' + row.numero_trabajo,
      tarea_actual: row.tarea_actual,
      unidades: row.unidades,
      medidas: `${row.alto}x${row.ancho}`
    }));
  
    res.json({ trabajos: trabajosFormateados });
  
  } catch (error) {
    console.error('Error al obtener trabajos pendientes:', error);
    res.status(500).json({ error: 'Error al obtener trabajos pendientes' });
  }  
});

psWorkflowDataRouter.get('/trabajos_envio', async (_req: Request, res: Response) => {
  const sql = `
    SELECT 
        wd.reference AS pedido,
        wt.id_order_detail AS articulo,
        wt.product_quantity AS unidades,
        wdm.ancho,
        wdm.alto,
        c.nombre AS casillero,
        t.nombre AS tarea_actual,
        CAST(
            CONCAT_WS(
              '/',
              ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
              COUNT(*) OVER (PARTITION BY wd.id_order)
            ) AS CHAR
          ) AS numero_trabajo
    FROM ps_workflow_tareas wt
    JOIN ps_workflow_data wd 
        ON wt.id_order = wd.id_order 
        AND wt.id_order_detail = wd.id_order_detail 
        AND wt.id_value = wd.id_value
    JOIN ps_workflow_data_medidas wdm 
        ON wdm.id_order_detail = wd.id_order_detail 
        AND wdm.id_plugins = wd.id_plugins
    JOIN tarea t ON wt.id_tarea = t.id
    JOIN maquina m ON wt.id_maquina = m.id
    LEFT JOIN casillero c 
          ON c.pedido = CASE 
              WHEN EXISTS (
                SELECT 1 
                FROM casillero c1 
                WHERE c1.pedido = CONCAT(wd.reference, '-', wd.id_order_detail)
              )
              THEN CONCAT(wd.reference, '-', wd.id_order_detail)
              WHEN wt.grupo_trabajo IS NOT NULL 
              THEN CONCAT(wd.reference, '-', wt.grupo_trabajo)
              ELSE NULL
            END
    WHERE m.id_tipomaquina = 6
      AND wt.estado <> 4
      AND NOT EXISTS (
          SELECT 1 
          FROM ps_workflow_tareas wt2
          JOIN maquina m2 ON wt2.id_maquina = m2.id
          WHERE wt2.id_order_detail = wt.id_order_detail
            AND wt2.estado <> 4
            AND m2.id_tipomaquina <> 6
      )
    ORDER BY DATE(wd.fecha_entrega) ASC;
  `;

  try {
    const result: any[] = await sequelize.query(sql, { type: QueryTypes.SELECT });

    const trabajosFormateados = result.map(row => ({
      casillero: row.casillero || '-',
      pedido: row.pedido,
      articulo: row.articulo + '-' + row.numero_trabajo,
      tarea_actual: row.tarea_actual,
      unidades: row.unidades,
      medidas: `${row.alto}x${row.ancho}`
    }));

    res.json({ trabajos: trabajosFormateados });
  } catch (error) {
    console.error('Error al obtener trabajos de envío:', error);
    res.status(500).json({ error: 'Error al obtener trabajos de envío' });
  }
});

psWorkflowDataRouter.post('/asignar_trabajo_by_id', async (req: Request, res: Response) => {
  const { id_operario, id_trabajo, idTipomaquina } = req.body;

  if (!id_operario || !id_trabajo || !idTipomaquina) {
    return res.status(400).json({ error: 'Los parámetros id_operario, id_trabajo y idTipomaquina son obligatorios' });
  }

  try {
    // 1. Actualizar el trabajo con el operario
    await sequelize.query(
      `UPDATE ps_workflow_tareas SET id_operario = :id_operario, estado = 3 WHERE id = :id_trabajo`,
      {
        type: QueryTypes.UPDATE,
        replacements: { id_operario, id_trabajo },
      }
    );

    // 2. Obtener los trabajos actualizados (igual que /trabajos_embalaje)
    const trabajos = await sequelize.query(
      `
        WITH TareasPendientes AS (
          SELECT 
              wt.id AS trabajo_id,
              wt.id_order,
              wt.id_order_detail,
              wd.reference,
              wd.product_nombre,
              wt.product_quantity,
              wd.fecha_entrega,
              wt.estado AS estado,
              t.nombre AS nombre_tarea,
              wdm.ancho,
              t.orden AS orden_tarea,
              wdm.alto,
              c.nombre AS casillero,
              wi.siglas AS caracteristicas,
              o.nombre AS operario
          FROM ps_workflow_tareas wt
          LEFT JOIN operario o ON wt.id_operario = o.id
          JOIN ps_workflow_data wd 
              ON wt.id_order = wd.id_order 
              AND wt.id_order_detail = wd.id_order_detail 
              AND wt.id_value = wd.id_value
          JOIN ps_workflow_data_medidas wdm 
              ON wdm.id_order_detail = wd.id_order_detail 
              AND wdm.id_plugins = wd.id_plugins
          LEFT JOIN casillero c 
            ON c.pedido = CASE 
                WHEN EXISTS (
                  SELECT 1 
                  FROM casillero c1 
                  WHERE c1.pedido = CONCAT(wd.reference, '-', wd.id_order_detail)
                )
                THEN CONCAT(wd.reference, '-', wd.id_order_detail)
                WHEN wt.grupo_trabajo IS NOT NULL 
                THEN CONCAT(wd.reference, '-', wt.grupo_trabajo)
                ELSE NULL
              END
          JOIN tarea t ON wt.id_tarea = t.id
          JOIN maquina m ON wt.id_maquina = m.id
          LEFT JOIN ps_workflow_material wm ON wd.id_value = wm.id_value
          LEFT JOIN material mat ON wm.id_material = mat.id
          LEFT JOIN ps_workflow_iconos wi ON wi.id_value = wd.id_value
          WHERE m.id_tipomaquina = :idTipomaquina
          AND wd.current_state IN (3, 33) 
          AND wt.estado <> 4
        ), TareasPrevias AS (
          SELECT wt.id_order_detail, MAX(t.orden) AS ultima_tarea_completada
          FROM ps_workflow_tareas wt
          JOIN tarea t ON wt.id_tarea = t.id
          WHERE wt.estado = 4
          GROUP BY wt.id_order_detail
        )
        SELECT tp.* 
        FROM TareasPendientes tp
        JOIN TareasPrevias taprev 
            ON tp.id_order_detail = taprev.id_order_detail
        WHERE tp.orden_tarea = (
            SELECT MIN(t2.orden)
            FROM ps_workflow_tareas wt2
            JOIN tarea t2 ON wt2.id_tarea = t2.id
            WHERE wt2.id_order_detail = tp.id_order_detail
            AND t2.orden > taprev.ultima_tarea_completada
            AND wt2.estado <> 4
        )
        ORDER BY tp.orden_tarea ASC, DATE(tp.fecha_entrega) ASC;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idTipomaquina },
      }
    );

    if (!trabajos.length) {
      return res.json({ totalTrabajos: 0, pedidosPendientes: [] });
    }

    const pedidosMap: Record<string, any> = {};
    let totalTrabajos = 0;

    trabajos.forEach((row: any) => {
      const referencia = row.reference;

      if (!pedidosMap[referencia]) {
        pedidosMap[referencia] = {
          pedido: referencia,
          fecha: row.fecha_entrega,
          operario: row.operario,
          trabajos: [],
          bultosAgrupados: [],
          selectedTrabajos: []
        };
      }

      pedidosMap[referencia].trabajos.push({
        trabajo_id: row.trabajo_id,
        articulo: row.id_order_detail,
        casillero: row.casillero,
        caja: 'X',
        tipo: 'Tipo desconocido',
        caracteristicas: '-',
        unidades: row.product_quantity,
        unidadesDisponibles: row.product_quantity,
        ancho: row.ancho,
        alto: row.alto
      });

      totalTrabajos++;
    });

    res.json({ success: true, 
               message: 'Trabajo asignado correctamente', 
               totalTrabajos: totalTrabajos,
               pedidosPendientes: Object.values(pedidosMap)
            });

  } catch (error) {
    console.error('Error al asignar trabajo o recuperar datos:', error);
    res.status(500).json({ error: 'Error al asignar trabajo o recuperar trabajos' });
  }
});

psWorkflowDataRouter.post('/desasignar_trabajo_by_id', async (req: Request, res: Response) => {
  const { id_trabajo, idTipomaquina } = req.body;

  if (!id_trabajo || !idTipomaquina) {
    return res.status(400).json({ error: 'Los parámetros id_trabajo y idTipomaquina son obligatorios' });
  }

  // Aseguramos que siempre sea un array de números
  const tipos = Array.isArray(idTipomaquina)
    ? idTipomaquina.map(Number)
    : [Number(idTipomaquina)];

  try {
    // 1️⃣ Desasignar el trabajo concreto
    //    Sólo si está en estado = 3 (en proceso) y asignado a este operario
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas wt
      JOIN maquina m
        ON wt.id_maquina = m.id
      SET
        wt.id_operario       = NULL,
        wt.fecha_realizacion = NULL,
        wt.estado            = 1
      WHERE
        wt.id           = :id_trabajo
        AND wt.estado         = 3
        AND m.id_tipomaquina IN (:tipos)
      `,
      {
        replacements: { id_trabajo, tipos }
      }
    );

    // 2️⃣ Recuperar de nuevo todos los trabajos pendientes para esa máquina
    const trabajos = await sequelize.query(
      `
      WITH TareasPendientes AS (
        SELECT 
            wt.id            AS trabajo_id,
            wt.id_order,
            wt.id_order_detail,
            wd.reference,
            wd.product_nombre,
            wt.product_quantity,
            wd.fecha_entrega,
            wt.estado        AS estado,
            t.nombre         AS nombre_tarea,
            wdm.ancho,
            wdm.alto,
            t.orden          AS orden_tarea,
            CAST(
              CONCAT_WS(
                '/',
                ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
                COUNT(*)     OVER (PARTITION BY wd.id_order)
              )
              AS CHAR
            ) AS numero_trabajo
        FROM ps_workflow_tareas wt
        JOIN ps_workflow_data wd 
          ON wt.id_order        = wd.id_order 
         AND wt.id_order_detail = wd.id_order_detail 
         AND wt.id_value        = wd.id_value
        JOIN ps_workflow_data_medidas wdm 
          ON wdm.id_order_detail = wd.id_order_detail 
         AND wdm.id_plugins      = wd.id_plugins
        JOIN tarea t 
          ON wt.id_tarea = t.id
        JOIN maquina m 
          ON wt.id_maquina = m.id
        LEFT JOIN ps_workflow_material wm 
          ON wd.id_value = wm.id_value
        LEFT JOIN material mat 
          ON wm.id_material = mat.id
        WHERE m.id_tipomaquina = :idTipomaquina
          AND wd.current_state  IN (3, 33)
          AND wt.estado        <> 4
      ),
      TareasPrevias AS (
        SELECT 
          wt.id_order_detail, 
          MAX(t.orden) AS ultima_tarea_completada
        FROM ps_workflow_tareas wt
        JOIN tarea t 
          ON wt.id_tarea = t.id
        WHERE wt.estado = 4
        GROUP BY wt.id_order_detail
      )
      SELECT tp.* 
      FROM TareasPendientes tp
      JOIN TareasPrevias taprev 
        ON tp.id_order_detail = taprev.id_order_detail
      WHERE tp.orden_tarea = (
        SELECT MIN(t2.orden)
        FROM ps_workflow_tareas wt2
        JOIN tarea t2 
          ON wt2.id_tarea = t2.id
        WHERE wt2.id_order_detail = tp.id_order_detail
          AND t2.orden > taprev.ultima_tarea_completada
          AND wt2.estado <> 4
      )
      ORDER BY
        tp.orden_tarea ASC,
        DATE(tp.fecha_entrega) ASC;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idTipomaquina }
      }
    );

    // 3️⃣ Formatear la respuesta igual que en `/asignar_trabajo_by_id`
    if (!trabajos.length) {
      return res.json({ totalTrabajos: 0, pedidosPendientes: [] });
    }

    const pedidosMap: Record<string, any> = {};
    let totalTrabajos = 0;

    trabajos.forEach((row: any) => {
      const referencia = row.reference;
      if (!pedidosMap[referencia]) {
        pedidosMap[referencia] = {
          pedido: referencia,
          fecha: row.fecha_entrega,
          operario: null,
          trabajos: [],
          bultosAgrupados: [],
          selectedTrabajos: []
        };
      }

      pedidosMap[referencia].trabajos.push({
        trabajo_id: row.trabajo_id,
        articulo: row.id_order_detail,
        casillero: null,
        caja: 'X',
        tipo: 'Tipo desconocido',
        caracteristicas: '-',
        unidades: row.product_quantity,
        unidadesDisponibles: row.product_quantity,
        ancho: row.ancho,
        alto: row.alto
      });

      totalTrabajos++;
    });

    res.json({
      success: true,
      message: 'Trabajo desasignado correctamente',
      totalTrabajos,
      pedidosPendientes: Object.values(pedidosMap)
    });

  } catch (error) {
    console.error('Error al desasignar trabajo o recuperar tareas:', error);
    res.status(500).json({ error: 'Error al desasignar trabajo o recuperar tareas' });
  }
});

psWorkflowDataRouter.get('/operario_tareas_existentes', async (req: Request, res: Response) => {
  const { idTipomaquina, id_operario } = req.query;

  if (!idTipomaquina || !id_operario) {
    return res.status(400).json({ error: 'El parámetro idTipomaquina y id_operario son obligatorios' });
  }

  // Aseguramos de que siempre sea un array, incluso si solo viene uno
  const tipos = Array.isArray(idTipomaquina) ? idTipomaquina.map(Number) : [Number(idTipomaquina)];

  try {
    // 1. Obtener las máquinas del tipo indicado junto con los trabajos asignados
    const maquinasConTrabajos = await sequelize.query(
      `
      WITH TareasPendientes AS (
        SELECT 
            wt.id AS trabajo_id,
            wt.id_order,
            wt.id_order_detail,
            wd.reference,
            wd.product_nombre AS articulo,
            wt.product_quantity AS unidades,
            wd.fecha_entrega AS fechaEntrega,
            wt.estado AS id_estado_trabajo,
            t.orden AS orden_tarea,
            t.nombre AS nombre_tarea,
            wt.id_tarea,
            wt.id_maquina,
            m.nombre AS maquina_nombre,
            m.id_tipomaquina,
            m.perfiles_color,
            mat.id AS id_material,
            mat.nombre AS material_nombre,
            wt.grupo_trabajo,
            wdm.ancho,
            wdm.alto,
            c.nombre AS casillero_nombre,
          CAST(
            CONCAT_WS(
              '/',
              ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
              COUNT(*)     OVER (PARTITION BY wd.id_order)
            )
            AS CHAR
          ) AS numero_trabajo,
            o.nombre AS operario_nombre
        FROM ps_workflow_tareas wt
        JOIN ps_workflow_data wd 
            ON wt.id_order = wd.id_order 
          AND wt.id_order_detail = wd.id_order_detail 
          AND wt.id_value = wd.id_value
        JOIN ps_workflow_data_medidas wdm 
            ON wdm.id_order_detail = wd.id_order_detail 
          AND wdm.id_plugins = wd.id_plugins
        JOIN tarea t ON wt.id_tarea = t.id
        JOIN maquina m ON wt.id_maquina = m.id
        LEFT JOIN operario o ON wt.id_operario = o.id
        LEFT JOIN casillero c 
          ON c.pedido = CASE 
              WHEN EXISTS (
                SELECT 1 
                FROM casillero c1 
                WHERE c1.pedido = CONCAT(wd.reference, '-', wd.id_order_detail)
              )
              THEN CONCAT(wd.reference, '-', wd.id_order_detail)
              WHEN wt.grupo_trabajo IS NOT NULL 
              THEN CONCAT(wd.reference, '-', wt.grupo_trabajo)
              ELSE NULL
            END
        LEFT JOIN ps_workflow_material wm ON wd.id_value = wm.id_value
        LEFT JOIN material mat ON wm.id_material = mat.id
        WHERE m.id_tipomaquina IN (:tipos)
          AND wd.current_state IN (3, 33) 
          AND wt.estado = 3 -- Solo trabajos en proceso
          AND wt.id_operario = :id_operario
      ),
      TareasPrevias AS (
        SELECT wt.id_order_detail, MAX(t.orden) AS ultima_tarea_completada
        FROM ps_workflow_tareas wt
        JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.estado = 4 -- Solo tareas completadas
        GROUP BY wt.id_order_detail
      )
      SELECT tp.* 
      FROM TareasPendientes tp
      JOIN TareasPrevias taprev 
          ON tp.id_order_detail = taprev.id_order_detail
      WHERE tp.orden_tarea = (
          SELECT MIN(t2.orden)
          FROM ps_workflow_tareas wt2
          JOIN tarea t2 ON wt2.id_tarea = t2.id
          WHERE wt2.id_order_detail = tp.id_order_detail
            AND t2.orden > taprev.ultima_tarea_completada
            AND wt2.estado <> 4 -- Debe estar pendiente
      )
      ORDER BY tp.orden_tarea ASC, DATE(tp.fechaEntrega) ASC;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { tipos, id_operario },
      }
    );

    if (!maquinasConTrabajos.length) {
      return res.json({ totalTrabajos: 0, maquinasConTrabajos: [] });
    }

    // 2. Agrupar trabajos por máquina y luego por grupo_trabajo
    const trabajosPorMaquina: Record<string, any> = {};

    maquinasConTrabajos.forEach((row: any) => {
      const maquinaId = row.id_maquina;
      const grupoId = row.grupo_trabajo || `sin_grupo_${row.trabajo_id}`;

      if (!trabajosPorMaquina[maquinaId]) {
        trabajosPorMaquina[maquinaId] = {
          maquina_id: maquinaId,
          maquina_nombre: row.maquina_nombre || '-',
          grupos: {},
        };
      }

      if (!trabajosPorMaquina[maquinaId].grupos[grupoId]) {
        trabajosPorMaquina[maquinaId].grupos[grupoId] = {
          grupo_id: grupoId,
          trabajos: [],
        };
      }

      const trabajoData = {
        id: row.trabajo_id,
        id_order: row.id_order,
        id_order_detail: row.id_order_detail,
        articulo: row.articulo,
        unidades: row.unidades,
        ancho: row.ancho,
        alto: row.alto,
        reference: row.reference,
        fechaEntrega: row.fechaEntrega,
        id_estado_trabajo: row.id_estado_trabajo,
        casillero_nombre: row.casillero_nombre,
        id_tipomaquina: row.id_tipomaquina,
        operario: row.operario_nombre
      };
      
      trabajosPorMaquina[maquinaId].grupos[grupoId].trabajos.push(trabajoData);
    });

    // 3. Formatear la respuesta final
    const response = Object.values(trabajosPorMaquina).map((maquina: any) => ({
      ...maquina,
      grupos: Object.values(maquina.grupos),
    }));

    res.json({
      totalTrabajos: maquinasConTrabajos.length,
      maquinasConTrabajos: response,
    });
  } catch (error) {
    console.error('Error al obtener las tareas del operario:', error);
    res.status(500).json({ error: 'Error al obtener las tareas del operario' });
  }
});

// psWorkflowDataRouter.post('/asignar_trabajo', async (req: Request, res: Response) => {
//   const { idTipomaquina, id_operario } = req.body;

//   if (!idTipomaquina || !id_operario) {
//     return res.status(400).json({ error: 'El parámetro idTipomaquina y id_operario son obligatorios' });
//   }

//   // Aseguramos de que siempre sea un array, incluso si solo viene uno
//   const tipos = Array.isArray(idTipomaquina)
//   ? idTipomaquina.map(Number)
//   : [Number(idTipomaquina)];

//   try {
//     // 1️⃣ Obtener el modo activado
//     const [modoActivado]: any = await sequelize.query(
//       `SELECT nombre FROM modo_activado WHERE activo = true LIMIT 1`,
//       { type: QueryTypes.SELECT }
//     );
//     if (!modoActivado) {
//       return res.status(400).json({ error: 'No hay un modo activado en este momento' });
//     }
//     const modo = modoActivado.nombre;

//     // 2️⃣ Obtener trabajos disponibles que cumplan que las tareas previas estén completadas
//     const trabajos = await sequelize.query(
//       `
//       WITH TareasPendientes AS (
//         SELECT 
//             wt.id AS trabajo_id,
//             wt.id_order,
//             wt.id_order_detail,
//             wd.reference,
//             wd.product_nombre,
//             wt.product_quantity,
//             wd.fecha_entrega,
//             wt.estado,
//             t.orden AS orden_tarea,
//             t.nombre AS nombre_tarea,
//             wt.id_tarea,
//             wt.id_maquina,
//             wt.id_operario,
//             m.usuarios_simultaneos
//         FROM ps_workflow_tareas wt
//         JOIN ps_workflow_data wd 
//           ON wt.id_order = wd.id_order 
//          AND wt.id_order_detail = wd.id_order_detail 
//          AND wt.id_value = wd.id_value
//         JOIN tarea t ON wt.id_tarea = t.id
//         JOIN maquina m ON wt.id_maquina = m.id
//         WHERE wd.current_state IN (3, 33) 
//           AND wt.estado <> 4         -- Solo trabajos pendientes
//           AND m.id_tipomaquina IN (:tipos)
//       ),
//       TareasPrevias AS (
//         SELECT wt.id_order_detail, MAX(t.orden) AS ultima_tarea_completada
//         FROM ps_workflow_tareas wt
//         JOIN tarea t ON wt.id_tarea = t.id
//         WHERE wt.estado = 4         -- Solo tareas completadas
//         GROUP BY wt.id_order_detail
//       )
//       SELECT tp.* 
//       FROM TareasPendientes tp
//       JOIN TareasPrevias taprev 
//           ON tp.id_order_detail = taprev.id_order_detail
//       WHERE tp.orden_tarea = (
//           SELECT MIN(t2.orden)
//           FROM ps_workflow_tareas wt2
//           JOIN tarea t2 ON wt2.id_tarea = t2.id
//           WHERE wt2.id_order_detail = tp.id_order_detail
//             AND t2.orden > taprev.ultima_tarea_completada
//             AND wt2.estado <> 4   -- Debe estar pendiente
//       )
//       ORDER BY DATE(tp.fecha_entrega) ASC
//       `,
//       { type: QueryTypes.SELECT, replacements: { tipos } }
//     );

//     if (!trabajos.length) {
//       return res.json({ success: false, message: 'No hay trabajos disponibles para asignar' });
//     }

//     // 3️⃣ Filtrar trabajos que no tengan ya asignado un operario en máquinas que permiten solo 1 usuario
//     const trabajosFiltrados = trabajos.filter((trabajo: any) => {
//       if (trabajo.usuarios_simultaneos === 1) {
//         return !trabajo.id_operario; // Solo si no está asignado
//       }
//       return true;
//     });

//     if (!trabajosFiltrados.length) {
//       return res.json({ success: false, message: 'No hay trabajos disponibles para esta máquina y operario' });
//     }

//     // 4️⃣ Seleccionar el trabajo más adecuado según el modo (en este ejemplo, para los modos ORDINARIO, EXTRAORDINARIO y POR_PUESTO, se selecciona el primero)
//     let trabajoSeleccionado: any;
//     if (['ORDINARIO', 'EXTRAORDINARIO', 'POR_PUESTO'].includes(modo)) {
//       trabajoSeleccionado = trabajosFiltrados[0];
//     }

//     if (!trabajoSeleccionado) {
//       return res.json({ success: false, message: 'No se encontró un trabajo adecuado para asignar' });
//     }

//     const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

//     // 5️⃣ Asignar el trabajo al operario (actualizar el registro en ps_workflow_tareas)
//     await sequelize.query(
//       `UPDATE ps_workflow_tareas
//        SET id_operario = :id_operario, fecha_realizacion = :fecha, estado = 3
//        WHERE id = :trabajo_id`,
//       {
//         type: QueryTypes.UPDATE,
//         replacements: { id_operario, trabajo_id: trabajoSeleccionado.trabajo_id, fecha: fecha },
//       }
//     );

//     res.json({ success: true, message: 'Trabajo asignado correctamente', trabajo: trabajoSeleccionado });
//   } catch (error) {
//     console.error('Error al asignar trabajo:', error);
//     res.status(500).json({ error: 'Error al asignar trabajo' });
//   }
// });

// Endpoint: asignar_trabajo con validación por modo y orden personalizada
psWorkflowDataRouter.post('/asignar_trabajo', async (req, res) => {
  const { idTipomaquina, id_operario } = req.body;

  if (!idTipomaquina || !id_operario) {
    return res.status(400).json({ error: 'El parámetro idTipomaquina y id_operario son obligatorios' });
  }

  const tipos = Array.isArray(idTipomaquina) ? idTipomaquina.map(Number) : [Number(idTipomaquina)];

  try {
    const [modoActivado]: any = await sequelize.query(
      `SELECT nombre FROM modo_activado WHERE activo = true LIMIT 1`,
      { type: QueryTypes.SELECT }
    );

    if (!modoActivado) {
      return res.status(400).json({ error: 'No hay un modo activado en este momento' });
    }

    const modo = modoActivado.nombre.toLowerCase();
    const tablaModo = `modo_${modo}`;

    const preferencias = await sequelize.query(
      `SELECT maquinaId, orden FROM ${tablaModo} WHERE operarioId = :id_operario AND activo = 1`,
      {
        type: QueryTypes.SELECT,
        replacements: { id_operario },
      }
    );

    const maquinasPermitidas = preferencias.map((p: any) => p.maquinaId);
    const ordenPreferencias = new Map(preferencias.map((p: any) => [p.maquinaId, p.orden]));

    const trabajos = await sequelize.query(
      `
      WITH TareasPendientes AS (
        SELECT 
          wt.id AS trabajo_id,
          wt.id_order,
          wt.id_order_detail,
          wd.reference,
          wd.product_nombre,
          wt.product_quantity,
          wd.fecha_entrega,
          wd.nombre_seleccion,
          wt.estado,
          t.orden AS orden_tarea,
          t.nombre AS nombre_tarea,
          wt.id_tarea,
          wt.id_maquina,
          wt.id_operario,
          m.usuarios_simultaneos
        FROM ps_workflow_tareas wt
        JOIN ps_workflow_data wd 
          ON wt.id_order = wd.id_order 
         AND wt.id_order_detail = wd.id_order_detail 
         AND wt.id_value = wd.id_value
        JOIN tarea t ON wt.id_tarea = t.id
        JOIN maquina m ON wt.id_maquina = m.id
        WHERE wd.current_state IN (3, 33) 
          AND wt.estado <> 4
          AND m.id_tipomaquina IN (:tipos)
      ),
      TareasPrevias AS (
        SELECT wt.id_order_detail, MAX(t.orden) AS ultima_tarea_completada
        FROM ps_workflow_tareas wt
        JOIN tarea t ON wt.id_tarea = t.id
        WHERE wt.estado = 4
        GROUP BY wt.id_order_detail
      )
      SELECT tp.* 
      FROM TareasPendientes tp
      JOIN TareasPrevias taprev 
        ON tp.id_order_detail = taprev.id_order_detail
      WHERE tp.orden_tarea = (
        SELECT MIN(t2.orden)
        FROM ps_workflow_tareas wt2
        JOIN tarea t2 ON wt2.id_tarea = t2.id
        WHERE wt2.id_order_detail = tp.id_order_detail
          AND t2.orden > taprev.ultima_tarea_completada
          AND wt2.estado <> 4
      )
      ORDER BY
        DATE(tp.fecha_entrega) ASC,
        FIELD(tp.nombre_seleccion, 'Expréss', 'Estándar', 'SemiRelax', 'Relax')
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { tipos },
      }
    );

    if (!trabajos.length) {
      return res.json({ success: false, message: 'No hay trabajos disponibles para asignar' });
    }

    const trabajosFiltrados: any = trabajos.filter((trabajo: any) => {
      if (trabajo.usuarios_simultaneos === 1 && trabajo.id_operario) return false;
      return maquinasPermitidas.includes(trabajo.id_maquina);
    });

    if (!trabajosFiltrados.length) {
      return res.json({ success: false, message: 'No hay trabajos disponibles para esta máquina y operario' });
    }

    trabajosFiltrados.sort((a: any, b: any) => {
      const ordenA = ordenPreferencias.get(a.id_maquina) ?? Infinity;
      const ordenB = ordenPreferencias.get(b.id_maquina) ?? Infinity;
      return ordenA - ordenB;
    });

    const trabajoSeleccionado: any = trabajosFiltrados[0];
    const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

    await sequelize.query(
      `UPDATE ps_workflow_tareas
       SET id_operario = :id_operario, fecha_realizacion = :fecha, estado = 3
       WHERE id = :trabajo_id`,
      {
        type: QueryTypes.UPDATE,
        replacements: { id_operario, trabajo_id: trabajoSeleccionado.trabajo_id, fecha },
      }
    );

    res.json({ success: true, message: 'Trabajo asignado correctamente', trabajo: trabajoSeleccionado });
  } catch (error) {
    console.error('Error al asignar trabajo:', error);
    res.status(500).json({ error: 'Error al asignar trabajo' });
  }
});

psWorkflowDataRouter.post('/desasignar_trabajo', async (req, res) => {
  const { idTipomaquina, id_operario } = req.body;

  if (!idTipomaquina || !id_operario) {
    return res.status(400).json({ error: 'El parámetro idTipomaquina y id_operario son obligatorios' });
  }

  // Aseguramos que siempre sea un array de números
  const tipos = Array.isArray(idTipomaquina)
    ? idTipomaquina.map(Number)
    : [Number(idTipomaquina)];

  try {
    // Nota: omitimos `type` para que Sequelize nos devuelva [results, metadata]
    const [ , metadata ] = await sequelize.query(
      `
      UPDATE ps_workflow_tareas wt
      JOIN maquina m
        ON wt.id_maquina = m.id
      SET
        wt.id_operario       = NULL,
        wt.fecha_realizacion = NULL,
        wt.estado            = 1
      WHERE
        wt.id_operario    = :id_operario
        AND wt.estado     = 3
        AND m.id_tipomaquina IN (:tipos)
      `,
      {
        replacements: { id_operario, tipos }
      }
    );

    // Ahora metadata.affectedRows contendrá el número de filas actualizadas
    const count = (metadata as any).affectedRows ?? 0;

    if (count === 0) {
      return res.json({ success: false, message: 'No se encontró ningún trabajo para desasignar' });
    }

    return res.json({
      success: true,
      message: `Se desasignaron correctamente ${count} trabajo(s).`
    });
  } catch (error) {
    console.error('Error al desasignar trabajo:', error);
    return res.status(500).json({ error: 'Error al desasignar trabajo' });
  }
});

psWorkflowDataRouter.get('/siguiente_tarea', async (req: Request, res: Response) => {
  const { idOperario } = req.query;

  if (!idOperario) {
    return res.status(400).json({ error: 'El parámetro id_operario es obligatorio' });
  }

  try {
    // 1. Obtener las tareas del operario con JOINs directos
    const tareas = await sequelize.query(
      `
      SELECT 
        wd.id AS trabajo_id,
        wd.reference,
        wd.product_nombre AS articulo,
        wt.product_quantity AS unidades,
        wd.fecha_entrega AS fechaEntrega,
        wm.ancho,
        wm.alto,
        wd.current_state AS id_estado_trabajo,
        wt.id_tarea,
        t.nombre AS tarea_nombre,
        t.orden AS orden_tarea,
        et.nombre AS estado_nombre
      FROM ps_workflow_data wd
      JOIN ps_workflow_tareas wt 
        ON wd.id_order_detail = wt.id_order_detail
       AND wd.id_order = wt.id_order
       AND wd.id_value = wt.id_value
      JOIN tarea t 
        ON wt.id_tarea = t.id
      JOIN estado_trabajo et 
        ON wd.current_state = et.id
      LEFT JOIN ps_workflow_data_medidas wm 
        ON wd.id_order_detail = wm.id_order_detail
       AND wd.id_plugins = wm.id_plugins
      WHERE wd.id_operario = :idOperario
        AND wd.current_state NOT IN (6) -- Excluir tareas completadas o canceladas
      ORDER BY t.orden ASC, DATE(wd.fecha_entrega) ASC
      LIMIT 1; -- Obtener la tarea con mayor prioridad y menor fecha de entrega
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idOperario },
      }
    );

    if (tareas.length === 0) {
      return res.status(404).json({ message: 'No hay tareas disponibles para este operario' });
    }

    res.json(tareas[0]); // Devolver la tarea con mayor prioridad y menor fecha de entrega
  } catch (error) {
    console.error('Error al obtener la siguiente tarea:', error);
    res.status(500).json({ error: 'Error al obtener la siguiente tarea' });
  }
});

psWorkflowDataRouter.post('/submitTrabajoRealizadoGrupoTrabajo', async (req: Request, res: Response) => {
  const { id_trabajo: idTrabajo, id_operario: idOperario } = req.body;

  try {
    const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

    // Obtener la tarea del trabajo desde `ps_workflow_tareas`
    const [tareaTrabajo]: any = await sequelize.query(
      `
      SELECT wt.id_tarea, wt.estado, wd.grupo_trabajo AS grupo
      FROM ps_workflow_tareas wt
      JOIN ps_workflow_data wd 
        ON wd.id_order_detail = wt.id_order_detail
       AND wd.id_order = wt.id_order
       AND wd.id_value = wt.id_value
      WHERE wd.id = :idTrabajo
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idTrabajo },
      }
    );

    if (!tareaTrabajo) {
      return res.status(404).json({ success: false, message: 'Trabajo no encontrado o ya realizado' });
    }

    const grupo = tareaTrabajo.grupo ?? 0;
    const idTarea = tareaTrabajo.id_tarea;

    if (grupo !== 0) {
      console.log('Actualizando grupo:', grupo, 'idTarea:', idTarea);

      // Actualizar todas las tareas del grupo en `ps_workflow_tareas`
      await sequelize.query(
        `
        UPDATE ps_workflow_tareas
        SET estado = 4, id_operario = :idOperario, fecha_realizacion = :fecha
        WHERE id_tarea = :idTarea AND id_order_detail IN (
          SELECT id_order_detail FROM ps_workflow_data WHERE grupo_trabajo = :grupo
        )
        `,
        {
          type: QueryTypes.UPDATE,
          replacements: { idOperario, fecha, grupo, idTarea },
        }
      );

      // Obtener las tareas del grupo
      const tareasGrupo: any = await sequelize.query(
        `
        SELECT wt.id_tarea, wd.id_order, wd.id_order_detail
        FROM ps_workflow_tareas wt
        JOIN ps_workflow_data wd 
          ON wd.id_order_detail = wt.id_order_detail
         AND wd.id_order = wt.id_order
         AND wd.id_value = wt.id_value
        WHERE wd.grupo_trabajo = :grupo
          AND wt.estado <> 5
        `,
        {
          type: QueryTypes.SELECT,
          replacements: { grupo },
        }
      );

      // Procesar cada tarea para habilitar la siguiente en la orden
      for (const tarea of tareasGrupo) {
        const siguienteTarea: any = await sequelize.query(
          `
          SELECT wt.id_tarea
          FROM ps_workflow_tareas wt
          JOIN ps_workflow_data wd 
            ON wd.id_order_detail = wt.id_order_detail
           AND wd.id_order = wt.id_order
           AND wd.id_value = wt.id_value
          WHERE wd.id_order_detail = :id_order_detail
            AND wt.estado NOT IN (4, 5)
          ORDER BY wt.id_tarea ASC
          LIMIT 1
          `,
          {
            type: QueryTypes.SELECT,
            replacements: {
              id_order_detail: tarea.id_order_detail,
            },
          }
        );

        if (siguienteTarea.length > 0) {
          const sigTarea = siguienteTarea[0].id_tarea;
          await sequelize.query(
            `
            UPDATE ps_workflow_tareas
            SET estado = 3
            WHERE id_tarea = :sigTarea
            `,
            {
              type: QueryTypes.UPDATE,
              replacements: { sigTarea },
            }
          );
        }
      }
    } else {
      console.log('Actualizando tarea específica, id:', idTrabajo);

      // Actualizar solo la tarea específica en `ps_workflow_tareas`
      await sequelize.query(
        `
        UPDATE ps_workflow_tareas
        SET estado = 4, id_operario = :idOperario, fecha_realizacion = :fecha
        WHERE id_tarea = :idTarea
      `,
        {
          type: QueryTypes.UPDATE,
          replacements: { idOperario, fecha, idTarea },
        }
      );

      // Obtener la siguiente tarea de la misma orden
      const siguienteTarea: any = await sequelize.query(
        `
        SELECT id_tarea
        FROM ps_workflow_tareas
        WHERE id_order_detail = (SELECT id_order_detail FROM ps_workflow_data WHERE id = :idTrabajo)
          AND estado NOT IN (4, 5)
        ORDER BY id_tarea ASC
        LIMIT 1
        `,
        {
          type: QueryTypes.SELECT,
          replacements: { idTrabajo },
        }
      );

      if (siguienteTarea.length > 0) {
        const sigTarea = siguienteTarea[0].id_tarea;
        await sequelize.query(
          `
          UPDATE ps_workflow_tareas
          SET estado = 3
          WHERE id_tarea = :sigTarea
          `,
          {
            type: QueryTypes.UPDATE,
            replacements: { sigTarea },
          }
        );
      }
    }

    res.json({ success: true, message: 'Trabajo actualizado correctamente' });
  } catch (error) {
    console.error('Error en submitTrabajoRealizadoGrupoTrabajo:', error);
    res.status(500).json({ success: false, error: 'Error al actualizar el trabajo' });
  }
});

psWorkflowDataRouter.get('/trabajos_maquetacion', [verificaToken], async (req: Request, res: Response) => {
  // const limit = parseInt(req.query.limit as string, 10) || 100;
  const offset = parseInt(req.query.offset as string, 10) || 0;

  try {
    // **1️⃣ Asegurar que las columnas necesarias existan en `ps_workflow_tareas`**
    const checkColumns = await sequelize.query(
      `SELECT COLUMN_NAME 
       FROM INFORMATION_SCHEMA.COLUMNS 
       WHERE TABLE_NAME = 'ps_workflow_tareas' 
       AND COLUMN_NAME IN ('estado', 'id_operario', 'fecha_realizacion', 'grupo_trabajo');`,
      { type: QueryTypes.SELECT }
    );
    
    const existingColumns = checkColumns.map((col: any) => col.COLUMN_NAME);
    
    // Si no existen todas las columnas, entonces ejecutamos ALTER TABLE
    if (!existingColumns.includes('estado') || 
        !existingColumns.includes('id_operario') || 
        !existingColumns.includes('fecha_realizacion') ||
        !existingColumns.includes('grupo_trabajo')) {
      
      await sequelize.query(
        `ALTER TABLE ps_workflow_tareas 
         ADD COLUMN IF NOT EXISTS estado INT DEFAULT 1,
         ADD COLUMN IF NOT EXISTS id_operario INT NULL,
         ADD COLUMN IF NOT EXISTS fecha_realizacion DATETIME NULL,
         ADD COLUMN IF NOT EXISTS grupo_trabajo INT NULL;`,
        { type: QueryTypes.RAW }
      );
    }    

    // **2️⃣ Obtener trabajos con los `JOIN` correctos**
    const trabajos = await sequelize.query(
      `
      SELECT
        wt.id,
        wd.id_order_detail,
        wd.reference,
        wd.product_nombre   AS articulo,
        wt.product_quantity AS unidades,
        wd.fecha_entrega,
        wm.ancho,
        wm.alto,
        wd.id_order,
        wd.id_value,
        wi.siglas,
        wi.color,
        wf.name  AS nombre_imagen,
        wt.grupo_trabajo,
        CAST(
          CONCAT_WS(
            '/',
            ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
            COUNT(*)     OVER (PARTITION BY wd.id_order)
          )
          AS CHAR
        ) AS numero_trabajo,
        ped.nombre_seleccion  AS plazo_entrega,
        ped2.nombre_seleccion AS carac_impresion
      FROM ps_workflow_data wd
      JOIN ps_workflow_tareas wt
        ON wd.id_order_detail = wt.id_order_detail
      AND wd.id_order        = wt.id_order
      AND wd.id_value        = wt.id_value
      LEFT JOIN ps_workflow_data_medidas wm
        ON wd.id_order_detail = wm.id_order_detail
      AND wd.id_plugins      = wm.id_plugins
      LEFT JOIN ps_workflow_iconos wi
        ON wi.id_value = wd.id_value
      LEFT JOIN ps_workflow_files wf
        ON wd.id_order_detail = wf.id_order_detail
      AND wd.id_order        = wf.id_order
      AND wd.id_plugins      = wf.id_plugins
      LEFT JOIN ps_workflow_data ped
        ON ped.reference            = wd.reference
      AND ped.id_order_detail      = wd.id_order_detail
      AND ped.nombre_campo_plugin = 'Plazo de Entrega'
      LEFT JOIN ps_workflow_data ped2
        ON ped2.reference            = wd.reference
      AND ped2.id_order_detail      = wd.id_order_detail
      AND ped2.nombre_campo_plugin  = 'Control ficheros'
      WHERE wt.id_tarea       IN (
          SELECT id FROM tarea WHERE nombre = 'Maquetación'
        )
        AND wt.estado         IN (1,2,3)
        AND wd.current_state  IN (3,33)
      ORDER BY
        DATE(wd.fecha_entrega) ASC,
        FIELD(ped.nombre_seleccion,
              'Expréss',
              'Estándar',
              'SemiRelax',
              'Relax'
        ),
        wd.reference ASC;
      `,
      {
        // replacements: { limit, offset },
        replacements: { offset },
        type: QueryTypes.SELECT,
      }
    );

    // **3️⃣ Si no hay resultados, retornar una respuesta vacía**
    if (trabajos.length === 0) {
      return res.json({
        total: 0,
        pedidos: [],
      });
    }

    // **4️⃣ Agrupar trabajos por pedido**
    const pedidos = trabajos.reduce((acumulador: any, trabajo: any) => {
      let pedido = acumulador.find((p: any) => p.reference === trabajo.reference);
      if (!pedido) {
        pedido = {
          pedido: trabajo.reference,
          fecha_entrega: trabajo.fecha_entrega,
          plazo_entrega:  trabajo.plazo_entrega || null,  // <-- aquí lo asignamos
          articulos: [],
        };
        acumulador.push(pedido);
      }

      // Agregar cada trabajo como un artículo del pedido
      pedido.articulos.push({
        id: trabajo.id,
        id_order_detail: trabajo.id_order_detail,
        articulo: trabajo.articulo,
        unidades: trabajo.unidades,
        fecha_entrega: trabajo.fecha_entrega,
        ancho: trabajo.ancho,
        alto: trabajo.alto,
        siglas: trabajo.siglas,
        color: trabajo.color,
        nombre_imagen: trabajo.nombre_imagen,
        numero_trabajo: trabajo.numero_trabajo, // Incluir el número de trabajo
        id_order: trabajo.id_order,
        id_value: trabajo.id_value,
        grupo_trabajo: trabajo.grupo_trabajo,
        carac_impresion: trabajo.carac_impresion
      });

      return acumulador;
    }, []);

    // **5️⃣ Responder con los pedidos agrupados**
    res.json({
      total: trabajos.length,
      pedidos,
    });

  } catch (error) {
    console.error('Error al obtener la lista de trabajos de maquetación:', error);
    res.status(500).json({ error: 'Error al obtener la lista de trabajos de maquetación' });
  }
});

psWorkflowDataRouter.post('/submitTrabajoRealizado', async (req: Request, res: Response) => {
  const { id_trabajo: idTrabajo, id_operario: idOperario } = req.body;

  try {
    const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

    // **1️⃣ Verificar parámetros obligatorios**
    if (!idTrabajo || !idOperario) {
      return res.status(400).json({ success: false, error: 'Faltan parámetros obligatorios: id_trabajo o id_operario' });
    }

    // **2️⃣ Verificar si el trabajo existe en `ps_workflow_tareas`**
    const [trabajo]: any = await sequelize.query(
      `
      SELECT id
      FROM ps_workflow_tareas
      WHERE id = :idTrabajo
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idTrabajo },
      }
    );

    if (!trabajo) {
      return res.status(404).json({ success: false, message: 'Trabajo no encontrado' });
    }

    // **3️⃣ Actualizar el estado del trabajo**
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET estado = 4, id_operario = :idOperario, fecha_realizacion = :fecha
      WHERE id = :idTrabajo
      `,
      {
        replacements: { idOperario, fecha, idTrabajo },
        type: QueryTypes.UPDATE,
      }
    );

    res.json({ success: true, message: 'Estado del trabajo actualizado correctamente' });

  } catch (error) {
    console.error('Error en submitEstado:', error);
    res.status(500).json({ success: false, error: 'Error al actualizar el estado del trabajo', details: error });
  }
});

psWorkflowDataRouter.post('/submitTrabajosRealizados', async (req: Request, res: Response) => {
  const { ids_trabajos, id_operario } = req.body;
  console.log('IDs de trabajos recibidos:', ids_trabajos);

  try {
    const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

    // **1️⃣ Validar parámetros obligatorios**
    if (!Array.isArray(ids_trabajos) || ids_trabajos.length === 0 || !id_operario) {
      return res.status(400).json({ success: false, error: 'Faltan parámetros obligatorios: ids_trabajos o id_operario' });
    }

    // **2️⃣ Obtener los trabajos y sus tareas desde `ps_workflow_tareas`**
    const trabajos: any = await sequelize.query(
      `
      SELECT wt.id
      FROM ps_workflow_tareas wt
      WHERE wt.id IN (:ids_trabajos)
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { ids_trabajos },
      }
    );

    if (trabajos.length === 0) {
      return res.status(404).json({ success: false, message: 'No se encontraron trabajos para actualizar' });
    }

    // **3️⃣ Marcar todas las tareas como realizadas**
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET estado = 4, id_operario = :id_operario, fecha_realizacion = :fecha
      WHERE id IN (:ids) 
      `,
      {
        replacements: {
          id_operario,
          fecha,
          ids: trabajos.map((t: any) => t.id),
        },
        type: QueryTypes.UPDATE,
      }
    );

    res.json({ success: true, message: 'Trabajos marcados como realizados correctamente' });

  } catch (error) {
    console.error('Error en submitTrabajosRealizados:', error);
    res.status(500).json({ success: false, error: 'Error al marcar los trabajos como realizados' });
  }
});

psWorkflowDataRouter.post('/submitEstado', async (req: Request, res: Response) => {
  const { id_trabajo: idTrabajo, id_operario: idOperario } = req.body;

  try {
    const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

    // **1️⃣ Verificar parámetros obligatorios**
    if (!idTrabajo || !idOperario) {
      return res.status(400).json({ success: false, error: 'Faltan parámetros obligatorios: id_trabajo o id_operario' });
    }

    // **2️⃣ Verificar si el trabajo existe en `ps_workflow_tareas`**
    const [trabajo]: any = await sequelize.query(
      `
      SELECT id
      FROM ps_workflow_tareas
      WHERE id = :idTrabajo
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idTrabajo },
      }
    );

    if (!trabajo) {
      return res.status(404).json({ success: false, message: 'Trabajo no encontrado' });
    }

    // **3️⃣ Actualizar el estado del trabajo**
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET estado = 3, id_operario = :idOperario, fecha_realizacion = :fecha
      WHERE id = :idTrabajo
      `,
      {
        replacements: { idOperario, fecha, idTrabajo },
        type: QueryTypes.UPDATE,
      }
    );

    res.json({ success: true, message: 'Estado del trabajo actualizado correctamente' });

  } catch (error) {
    console.error('Error en submitEstado:', error);
    res.status(500).json({ success: false, error: 'Error al actualizar el estado del trabajo', details: error });
  }
});

psWorkflowDataRouter.post('/submitEstados', async (req: Request, res: Response) => {
  const { ids_trabajos, id_operario } = req.body;

  try {
    const fecha = new Date().toISOString().slice(0, 19).replace('T', ' ');

    // **1️⃣ Verificar parámetros obligatorios**
    if (!ids_trabajos || !Array.isArray(ids_trabajos) || ids_trabajos.length === 0 || !id_operario) {
      return res.status(400).json({ success: false, error: 'Faltan parámetros obligatorios o los datos son incorrectos' });
    }

    // **2️⃣ Verificar que los trabajos existen en `ps_workflow_tareas`**
    const trabajos = await sequelize.query(
      `
      SELECT wt.id
      FROM ps_workflow_tareas wt
      WHERE wt.id IN (:ids_trabajos)
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { ids_trabajos },
      }
    );

    if (!trabajos.length) {
      return res.status(404).json({ success: false, message: 'No se encontraron tareas para los trabajos indicados' });
    }

    // **3️⃣ Actualizar estado, operario y fecha de realización de los trabajos**
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET estado = 3, id_operario = :id_operario, fecha_realizacion = :fecha
      WHERE id IN (:ids_trabajos)
      `,
      {
        replacements: { id_operario, fecha, ids_trabajos },
        type: QueryTypes.UPDATE,
      }
    );

    res.json({ success: true, message: 'Estados de los trabajos actualizados correctamente' });

  } catch (error) {
    console.error('Error en submitEstados:', error);
    res.status(500).json({ success: false, error: 'Error al actualizar los estados de los trabajos', details: error });
  }
});

psWorkflowDataRouter.get('/tipomaquina', async (req: Request, res: Response) => {
  const { id_tipomaquina } = req.query;

  try {
    if (!id_tipomaquina) {
      return res.status(400).json({ error: 'El parámetro id_tipomaquina es obligatorio' });
    }

    // **1️⃣ Obtener los trabajos directamente con JOIN**
    const partes = await sequelize.query(
      `
      SELECT 
        wd.id AS trabajo_id, wd.id_order_detail, wd.reference, wd.product_nombre, 
        wt.product_quantity, wd.fecha_entrega, wd.estado, 
        m.id AS maquina_id, m.nombre AS maquina_nombre
      FROM ps_workflow_data wd
      JOIN ps_workflow_tareas wt 
        ON wd.id_order_detail = wt.id_order_detail 
        AND wd.id_order = wt.id_order 
        AND wd.id_value = wt.id_value
      JOIN maquina m 
        ON wt.id_maquina = m.id
      WHERE m.id_tipomaquina = :id_tipomaquina
      ORDER BY DATE(wd.fecha_entrega) ASC;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_tipomaquina },
      }
    );

    if (!partes.length) {
      return res.json([]); // No hay trabajos asociados a ese tipo de máquina
    }

    res.json(partes);

  } catch (error) {
    console.error('Error al obtener los partes de trabajo:', error);
    res.status(500).json({ error: 'Error al obtener los partes de trabajo' });
  }
});

psWorkflowDataRouter.post('/agrupar', async (req: Request, res: Response) => {
  const { trabajos } = req.body;

  if (!trabajos || !Array.isArray(trabajos) || trabajos.length === 0) {
    return res.status(400).json({ error: 'Datos incompletos o formato incorrecto' });
  }

  try {
    // **1️⃣ Generar un `grupo_trabajo` único de 6 dígitos**
    let grupoId = Math.floor(100000 + Math.random() * 900000);
    let grupoIdExiste = true;

    while (grupoIdExiste) {
      const [resultado]: any = await sequelize.query(
        'SELECT 1 FROM ps_workflow_tareas WHERE grupo_trabajo = :grupoId LIMIT 1',
        { replacements: { grupoId }, type: QueryTypes.SELECT }
      );
      grupoIdExiste = resultado !== undefined;
      if (grupoIdExiste) {
        grupoId = Math.floor(100000 + Math.random() * 900000);
      }
    }

    // **2️⃣ Obtener información de los trabajos a agrupar**
    const idOrders = [...new Set(trabajos.map((t: any) => t.id_order))];
    const idOrderDetails = [...new Set(trabajos.map((t: any) => t.id_order_detail))];

    // **3️⃣ Obtener todas las tareas de los artículos dentro del pedido**
    const tareasRelacionadas = await sequelize.query(
      `
      SELECT wt.id
      FROM ps_workflow_tareas wt
      JOIN ps_workflow_data wd 
        ON wt.id_order_detail = wd.id_order_detail 
        AND wt.id_order = wd.id_order 
        AND wt.id_value = wd.id_value
      WHERE wd.id_order IN (:idOrders) 
      AND wd.id_order_detail IN (:idOrderDetails)
      `,
      { replacements: { idOrders, idOrderDetails }, type: QueryTypes.SELECT }
    );

    const tareasRelacionadasIds = tareasRelacionadas.map((t: any) => t.id);
    console.log('tareasRelacionadasIds', tareasRelacionadasIds);

    // **4️⃣ Actualizar `grupo_trabajo` en todas las tareas relacionadas**
    if (tareasRelacionadasIds.length > 0) {
      await sequelize.query(
        `
        UPDATE ps_workflow_tareas
        SET grupo_trabajo = :grupoId
        WHERE id IN (:tareasRelacionadasIds)
        `,
        { replacements: { grupoId, tareasRelacionadasIds }, type: QueryTypes.UPDATE }
      );
    }

    res.json({ message: 'Trabajos agrupados correctamente, incluyendo todas las tareas de los artículos', grupo_trabajo: grupoId });
  } catch (error) {
    console.error('Error en /agrupar:', error);
    res.status(500).json({ error: 'Error al agrupar trabajos y sus tareas' });
  }
});

psWorkflowDataRouter.post('/agrupar_corte', async (req: Request, res: Response) => {
  const { trabajos } = req.body;

  if (!trabajos || trabajos.length < 2) {
    return res.status(400).json({ error: 'Debe proporcionar al menos dos trabajos para agrupar' });
  }

  try {
    const trabajosIds = trabajos.map((t: any) => t.id);
    const reference = trabajos[0].reference;
    const idOrderDetails = [...new Set(trabajos.map((t: any) => t.id_order_detail))];
    const materialBase = trabajos[0].material;

    // **1️⃣ Verificar si todos los trabajos pertenecen al mismo material**
    const todosMismoMaterial = trabajos.every((t: any) => t.material === materialBase);
    if (!todosMismoMaterial) {
      return res.status(400).json({ error: 'Todos los trabajos deben pertenecer al mismo material' });
    }

    // **2️⃣ Obtener las tareas de cada trabajo**
    const tareasPorTrabajo = await sequelize.query(
      `
      SELECT wt.id, wd.id_order, wd.id_order_detail, wt.id_tarea, wt.orden
      FROM ps_workflow_data wd
      JOIN ps_workflow_tareas wt 
        ON wd.id_order_detail = wt.id_order_detail
        AND wd.id_order = wt.id_order
        AND wd.id_value = wt.id_value
      WHERE wt.id IN (:trabajosIds)
      ORDER BY wt.orden ASC
      `,
      { replacements: { trabajosIds }, type: QueryTypes.SELECT }
    );

    if (!tareasPorTrabajo.length) {
      return res.status(404).json({ error: 'No se encontraron tareas válidas para los trabajos' });
    }

    const tareasBase = tareasPorTrabajo
      .filter((t: any) => t.id === trabajosIds[0])
      .map((t: any) => t.id_tarea)
      .sort()
      .join(',');

    const todosIguales = tareasPorTrabajo.every((t: any) => {
      return (
        tareasPorTrabajo
          .filter((trabajo: any) => trabajo.id === t.id)
          .map((trabajo: any) => trabajo.id_tarea)
          .sort()
          .join(',') === tareasBase
      );
    });

    if (!todosIguales) {
      return res.status(400).json({ error: 'Los trabajos no tienen las mismas tareas programadas' });
    }

    // **3️⃣ Generar un `grupo_trabajo` único**
    let grupoId = Math.floor(100000 + Math.random() * 900000);
    let grupoIdExiste = true;

    while (grupoIdExiste) {
      const [resultado]: any = await sequelize.query(
        'SELECT 1 FROM ps_workflow_tareas WHERE grupo_trabajo = :grupoId LIMIT 1',
        { replacements: { grupoId }, type: QueryTypes.SELECT }
      );
      grupoIdExiste = resultado !== undefined;
      if (grupoIdExiste) {
        grupoId = Math.floor(100000 + Math.random() * 900000);
      }
    }

    // **4️⃣ Actualizar los trabajos con el `grupo_trabajo` en `ps_workflow_tareas`**
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET grupo_trabajo = :grupoId
      WHERE id IN (:trabajosIds)
      `,
      { replacements: { grupoId, trabajosIds }, type: QueryTypes.UPDATE }
    );

    // **5️⃣ Obtener y actualizar las tareas siguientes**
    const tareasSiguientes = await sequelize.query(
      `
      SELECT wt.id
      FROM ps_workflow_tareas wt
      JOIN ps_workflow_data wd 
        ON wt.id_order_detail = wd.id_order_detail 
        AND wt.id_order = wd.id_order 
        AND wt.id_value = wd.id_value
      WHERE wd.id_order IN (:idOrders)
        AND wd.id_order_detail IN (:idOrderDetails)
        AND wt.orden > :ordenTrabajoMin
      `,
      {
        replacements: {
          idOrders: [...new Set(tareasPorTrabajo.map((t: any) => t.id_order))],
          idOrderDetails,
          ordenTrabajoMin: Math.min(...tareasPorTrabajo.map((t: any) => t.orden)),
        },
        type: QueryTypes.SELECT,
      }
    );

    const tareasSiguientesIds = tareasSiguientes.map((t: any) => t.id);

    if (tareasSiguientesIds.length > 0) {
      await sequelize.query(
        `
        UPDATE ps_workflow_tareas
        SET grupo_trabajo = :grupoId
        WHERE id IN (:tareasSiguientesIds)
        `,
        { replacements: { grupoId, tareasSiguientesIds }, type: QueryTypes.UPDATE }
      );
    }

    res.json({ message: 'Trabajos y tareas posteriores agrupados exitosamente', grupo_trabajo: grupoId });
  } catch (error) {
    console.error('Error en agrupar_corte:', error);
    res.status(500).json({ error: 'Error al agrupar trabajos en corte y sus tareas posteriores' });
  }
});

psWorkflowDataRouter.post('/desagrupar', async (req: Request, res: Response) => {
  const { trabajos } = req.body;

  if (!Array.isArray(trabajos) || trabajos.length === 0) {
    return res.status(400).json({ error: 'Debe proporcionar al menos un trabajo para desagrupar' });
  }

  try {
    const trabajosIds = trabajos.map((t: any) => t.id);

    // **1️⃣ Obtener el grupo_trabajo de los trabajos**
    const gruposTrabajo = await sequelize.query(
      `
      SELECT DISTINCT grupo_trabajo
      FROM ps_workflow_tareas
      WHERE id IN (:trabajosIds) AND grupo_trabajo IS NOT NULL
      `,
      { replacements: { trabajosIds }, type: QueryTypes.SELECT }
    );

    if (!gruposTrabajo.length) {
      return res.status(400).json({ error: 'Los trabajos proporcionados no están agrupados' });
    }

    const gruposTrabajoIds = gruposTrabajo.map((g: any) => g.grupo_trabajo);

    // **2️⃣ Eliminar `grupo_trabajo` de los trabajos seleccionados**
    await sequelize.query(
      `
      UPDATE ps_workflow_tareas
      SET grupo_trabajo = NULL
      WHERE id IN (:trabajosIds)
      `,
      { replacements: { trabajosIds }, type: QueryTypes.UPDATE }
    );

    // **3️⃣ Obtener las tareas siguientes que pertenecían al mismo grupo**
    const tareasSiguientes = await sequelize.query(
      `
      SELECT wt.id
      FROM ps_workflow_tareas wt
      WHERE wt.grupo_trabajo IN (:gruposTrabajoIds)
      `,
      { replacements: { gruposTrabajoIds }, type: QueryTypes.SELECT }
    );

    const tareasSiguientesIds = tareasSiguientes.map((t: any) => t.id);

    // **4️⃣ Desagrupar las tareas siguientes**
    if (tareasSiguientesIds.length > 0) {
      await sequelize.query(
        `
        UPDATE ps_workflow_tareas
        SET grupo_trabajo = NULL
        WHERE id IN (:tareasSiguientesIds)
        `,
        { replacements: { tareasSiguientesIds }, type: QueryTypes.UPDATE }
      );
    }

    res.json({ message: 'Trabajos y tareas siguientes desagrupados correctamente' });

  } catch (error) {
    console.error('Error en /desagrupar:', error);
    res.status(500).json({ error: 'Error al desagrupar trabajos y sus tareas siguientes' });
  }
});

psWorkflowDataRouter.post('/verificar-insertar-rip', async (req: Request, res: Response) => {
  const { id_order, id_order_detail } = req.body;
  console.log('id_order', id_order);
  console.log('id_order_detail', id_order_detail);

  if (!id_order || !id_order_detail) {
    return res.status(400).json({ error: 'Faltan parámetros en la solicitud' });
  }

  try {
    // **1️⃣ Obtener todas las tareas del artículo en el parte de trabajo**
    const tareasActuales: any = await sequelize.query(
      `
      SELECT wt.*, t.id_tipo_tarea, wt.id_maquina, t.nombre
      FROM ps_workflow_tareas wt
      JOIN tarea t ON t.id = wt.id_tarea
      WHERE wt.id_order = :id_order
        AND wt.id_order_detail = :id_order_detail
      ORDER BY t.orden ASC;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_order, id_order_detail },
      }
    );

    // **2️⃣ Verificar si la tarea RIP (id_tipotarea = 3) ya existe**
    const existeRip = tareasActuales.some((t: any) => t.id_tipo_tarea === 5);

    if (existeRip) {
      return res.json({ message: 'La tarea RIP ya está insertada. No se requiere acción.' });
    }
 
    // **3️⃣ Obtener el id_maquina de la tarea con id_tipotarea = 1**
    const tareaImpresion = tareasActuales.find((t: any) => (t.id_tipo_tarea === 1 && t.nombre === 'Imprimir'));
    
    if (!tareaImpresion) {
      return res.status(400).json({ error: 'No se encontró una tarea de impresión (id_tipotarea = 1).' });
    }

    console.log('tareaImpresion', tareaImpresion);

    const idMaquinaRelacionada = tareaImpresion.id_maquina_relacionada;
    const idValue = tareaImpresion.id_value; 

    // **4️⃣ Obtener el id_maquina_relacionada y el id_tarea desde la tabla maquina**
    const maquinaRelacionada: any = await sequelize.query(
      `
      SELECT *
      FROM maquina
      WHERE id = :idMaquinaRelacionada
      LIMIT 1;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { idMaquinaRelacionada: idMaquinaRelacionada },
      }
    );

    if (!maquinaRelacionada.length) {
      return res.status(404).json({ error: 'No se encontró una máquina relacionada para la tarea RIP.' });
    }

    // const idMaquinaRelacionada = maquinaRelacionada[0].id_maquina_relacionada;
    const idTareaRip = maquinaRelacionada[0].id_tarea;
    const maquinaNombre = maquinaRelacionada[0].nombre;
    const maquinaRelacionadaRip = maquinaRelacionada[0].id_maquina_relacionada;

    // **5️⃣ Obtener la información de la tarea RIP desde la tabla tarea**
    const tareaRip: any = await sequelize.query(
      `
      SELECT id, nombre, descripcion, orden
      FROM tarea
      WHERE id = :id_tarea
      LIMIT 1;
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { id_tarea: idTareaRip },
      }
    );

    if (!tareaRip.length) {
      return res.status(404).json({ error: 'No se encontró la tarea RIP en la tabla tarea.' });
    }

    const nuevaTarea = tareaRip[0];

    // **7️⃣ Insertar la tarea RIP en `ps_workflow_tareas`**
    await sequelize.query(
      `
      INSERT INTO ps_workflow_tareas 
      (id_order, id_order_detail, id_value, id_tarea, tarea_nombre, descripcion, estado, orden, id_maquina, maquina_nombre, prioridad, id_maquina_relacionada, fecha_realizacion, grupo_trabajo, product_quantity, id_operario, param1) 
      VALUES 
      (:id_order, :id_order_detail, :id_value, :id_tarea, :tarea_nombre, :descripcion, 1, :orden, :id_maquina, :maquina_nombre, :prioridad, :id_maquina_relacionada, NULL, NULL, :product_quantity, NULL, :param1);
      `,
      {
        replacements: {
          id_order,
          id_order_detail,
          id_value: idValue,
          id_tarea: nuevaTarea.id,
          tarea_nombre: 'RIP',
          descripcion: 'RIP',
          orden: nuevaTarea.orden,
          id_maquina: idMaquinaRelacionada,
          maquina_nombre: maquinaNombre,
          prioridad: tareasActuales[0]?.prioridad,
          id_maquina_relacionada: maquinaRelacionadaRip,
          param1: tareasActuales[0]?.param1,
          product_quantity: tareaImpresion?.product_quantity
        },
        type: QueryTypes.INSERT,
      }
    );

    res.json({ message: 'Tarea RIP insertada correctamente.' });

  } catch (error) {
    console.error('Error en verificar-insertar-rip:', error);
    res.status(500).json({ error: 'Error al verificar/insertar la tarea RIP.' });
  }
});

psWorkflowDataRouter.get('/buscar-references', async (req, res) => {
  try {
    const texto = String(req.query.texto || '');

    if (texto.length < 3) {
      return res.status(400).json({ error: 'El texto debe tener al menos 3 caracteres' });
    }

    const results = await sequelize.query(
      `
      SELECT DISTINCT reference 
      FROM ps_workflow_data
      WHERE reference LIKE :texto
      ORDER BY reference DESC
      LIMIT 20
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { texto: `%${texto}%` }
      }
    );

    const references = results.map((r: any) => r.reference);
    res.json(references);
  } catch (err) {
    console.error('Error al buscar referencias:', err);
    res.status(500).json({ error: 'Error al buscar referencias' });
  }
});

psWorkflowDataRouter.get('/detalle-pedido/:reference', async (req, res) => {
  try {
    const { reference } = req.params;

    // Primero, obtener todos los id_order_detail únicos para ese reference
    const rows = await sequelize.query(
      `
      SELECT DISTINCT wd.id_order_detail
      FROM ps_workflow_data wd
      WHERE wd.reference = :reference
      `,
      {
        type: QueryTypes.SELECT,
        replacements: { reference }
      }
    );

    if (!rows || rows.length === 0) {
      return res.status(404).json({ error: 'No se encontraron artículos para ese reference' });
    }

    const detalles = [];

    for (const row of rows as any[]) {
      const id_order_detail = row.id_order_detail;

      // Ejecutar la misma consulta de parte_trabajo para cada id_order_detail
      const parteTrabajoData = await sequelize.query(
        `
        SELECT wd.*, 
         wt.id AS id_workflow_tarea, 
         t.nombre, 
         wt.id_maquina, 
         wt.id_tarea, 
         et.nombre AS estado_nombre, 
         op.nombre AS operario_nombre, 
         m.nombre AS maquina_nombre, 
         t.orden AS orden_tarea,
         wt.fecha_realizacion, 
         wt.estado AS estado,
         CAST(
          CONCAT_WS(
            '/',
            ROW_NUMBER() OVER (PARTITION BY wd.id_order ORDER BY wd.id_order_detail),
            COUNT(*)     OVER (PARTITION BY wd.id_order)
          )
          AS CHAR
        ) AS numero_trabajo,
        hc.id_casillero AS casillero_nombre
        FROM ps_workflow_data wd
        JOIN ps_workflow_tareas wt 
          ON wd.id_order_detail = wt.id_order_detail 
          AND wd.id_order = wt.id_order 
          AND wd.id_value = wt.id_value
        LEFT JOIN estado_trabajo et 
          ON wt.estado = et.id
        LEFT JOIN operario op 
          ON wt.id_operario = op.id
        LEFT JOIN maquina m 
          ON wt.id_maquina = m.id
        LEFT JOIN historial_casillero hc  
          ON hc.id_tarea = wt.id  
        LEFT JOIN casillero cas  
          ON hc.id_casillero = cas.nombre  
        LEFT JOIN tarea t 
          ON wt.id_tarea = t.id
        WHERE wd.reference = :reference 
          AND wd.id_order_detail = :id_order_detail
          AND wd.current_state = 3
          AND wt.id_tarea IS NOT NULL
        ORDER BY t.orden ASC;
        `,
        {
          type: QueryTypes.SELECT,
          replacements: { reference, id_order_detail }
        }
      );

      if (!parteTrabajoData || parteTrabajoData.length === 0) continue;

      detalles.push({
        id_order_detail,
        parte_trabajo: {
          tareas: parteTrabajoData,
        }
      });
    }

    res.json(detalles);
  } catch (err) {
    console.error('Error al obtener detalle del pedido:', err);
    res.status(500).json({ error: 'Error al obtener detalle del pedido' });
  }
});

// Actualizar un parte de trabajo por ID
psWorkflowDataRouter.put('/:id', async (req: Request, res: Response) => {
  const { id } = req.params;
  const { id_maquina: nuevoIdMaquina, ...resto } = req.body;

  try {
    // 1) Obtenemos el parte original (id_order, id_order_detail y su máquina actual)
    const [parteOriginal]: any = await sequelize.query(
      `SELECT id_order, id_order_detail, id_maquina
       FROM ps_workflow_tareas
       WHERE id = :id`,
      { 
        type: QueryTypes.SELECT,
        replacements: { id } 
      }
    );
    if (!parteOriginal) {
      return res.status(404).json({ error: 'Parte de trabajo no encontrado' });
    }
    const { id_order, id_order_detail, id_maquina: maquinaActual } = parteOriginal;

    // 2) De la máquina nueva (id = nuevoIdMaquina) extraemos los valores que necesitamos:
    //    - id_tarea --> la tarea a la que pasa este parte
    //    - id_maquina_relacionada --> para RIP
    const [maquinaSel]: any = await sequelize.query(
      `SELECT id_tarea AS id_tarea_seleccionada,
              id_maquina_relacionada AS id_maquina_relacionada_seleccionada,
              id_tipomaquina
       FROM maquina
       WHERE id = :nuevoIdMaquina`,
      {
        type: QueryTypes.SELECT,
        replacements: { nuevoIdMaquina }
      }
    );
    if (!maquinaSel) {
      return res.status(400).json({ error: 'Máquina seleccionada no encontrada' });
    }
    const {
      id_tarea_seleccionada,
      id_maquina_relacionada_seleccionada,
      id_tipomaquina
    } = maquinaSel;

    // 3) Si la máquina seleccionada es de tipo 1 (IMPRESIÓN)
    if (id_tipomaquina === 1) {
      // 3.1) Aseguramos que exista la máquina relacionada
      if (id_maquina_relacionada_seleccionada == null) {
        return res.status(400).json({
          error: 'La máquina elegida no tiene id_maquina_relacionada configurada'
        });
      }
      // 3.2) Obtenemos la tarea asociada a esa máquina relacionada
      const [maquinaRel]: any = await sequelize.query(
        `SELECT id_tarea AS id_tarea_maquina_relacionada
         FROM maquina
         WHERE id = :id_maquina_relacionada_seleccionada`,
        {
          type: QueryTypes.SELECT,
          replacements: { id_maquina_relacionada_seleccionada }
        }
      );
      if (!maquinaRel) {
        return res.status(400).json({
          error: 'Máquina relacionada no encontrada'
        });
      }
      const { id_tarea_maquina_relacionada } = maquinaRel;

      // 4.2) ACTUALIZAMOS EL PARTE QUE TIENE id_tipo_tarea = 5 PARA ESTE id_order/id_order_detail
      await sequelize.query(
        `UPDATE ps_workflow_tareas wt
         JOIN tarea t 
           ON wt.id_tarea = t.id
         SET 
           wt.id_maquina = :id_maquina_relacionada_seleccionada,
           wt.id_tarea   = :id_tarea_maquina_relacionada
         WHERE wt.id_order = :id_order
           AND wt.id_order_detail = :id_order_detail
           AND t.id_tipo_tarea = 5`,
        {
          type: QueryTypes.UPDATE,
          replacements: {
            id_maquina_relacionada_seleccionada,
            id_tarea_maquina_relacionada,
            id_order,
            id_order_detail
          }
        }
      );
    }
    // 4.1) SI NO es tipo 1, o tras el caso anterior, siempre actualizamos el propio parte que vino en el PUT
    //     con la máquina y tarea “seleccionadas”
    await sequelize.query(
      `UPDATE ps_workflow_tareas
       SET id_maquina = :nuevoIdMaquina,
           id_tarea   = :id_tarea_seleccionada
       WHERE id = :id`,
      {
        type: QueryTypes.UPDATE,
        replacements: {
          nuevoIdMaquina,
          id_tarea_seleccionada,
          id
        }
      }
    );

    // 5) Aplicamos cualquier otro campo que venga en el body (resto)
    if (Object.keys(resto).length) {
      const setClauses = Object.keys(resto)
        .map(key => `\`${key}\` = :${key}`)
        .join(', ');
      await sequelize.query(
        `UPDATE ps_workflow_tareas
         SET ${setClauses}
         WHERE id = :id`,
        {
          type: QueryTypes.UPDATE,
          replacements: { id, ...resto }
        }
      );
    }

    // 6) Recuperamos y devolvemos el parte actualizado
    const [parteActualizado]: any = await sequelize.query(
      `SELECT * 
       FROM ps_workflow_tareas
       WHERE id = :id`,
      {
        type: QueryTypes.SELECT,
        replacements: { id }
      }
    );
    return res.json(parteActualizado);

  } catch (error) {
    console.error('Error en PUT /:id →', error);
    return res.status(500).json({ error: 'Error al actualizar el parte de trabajo' });
  }
});

export default psWorkflowDataRouter;
