<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Custom\SQLConnection;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;

class OperacionesMasivasController extends Controller
{
    // -------------------------------------------------------
    // PANTALLA INICIAL
    // -------------------------------------------------------

    public function index()
    {
        $pendientes = $this->_pendientesDelUsuario();

        return view('operaciones_masivas.index', [
            'cantidadPendientes' => count($pendientes),
            'pendientes'         => $pendientes,
        ]);
    }

    // -------------------------------------------------------
    // ALTA MASIVA — PASO 1: CONFIGURACIÓN
    // -------------------------------------------------------

    public function altaPaso1()
    {
        $clientes = SQLConnection::backendStoreProcedure('LED_Clientes', array('SELECT', NULL, NULL, NULL, NULL, 0, env('PLATAFORMA')), 'select');
        return view('operaciones_masivas.alta.paso1_configuracion', compact('clientes'));
    }

    public function altaPaso1Guardar(Request $request)
    {
        session(['alta_masiva_origen' => 'paso1']);
        session()->forget('alta_masiva_id_config');
        $request->validate([
            'cliente_id' => 'required',
            'familia_id' => 'required',
            'filial_id'  => 'required',
        ]);

        // Resolver nombres para no hacer SPs extra después
        $cliente = SQLConnection::backendStoreProcedure('LED_Clientes', array('SELECT', $request->cliente_id, NULL, NULL, NULL, NULL, env('PLATAFORMA')), 'selectOne');
        $familias = SQLConnection::backendStoreProcedure('LN_familias_', array('search', NULL, NULL, $request->cliente_id, NULL, NULL, NULL), 'select');
        $familia  = collect($familias)->firstWhere('familia', $request->familia_id);
        $filiales = SQLConnection::backendStoreProcedure('backend_cliente_paises', array('obtener_cliente_paises', $request->cliente_id), 'select');
        $filial   = collect($filiales)->firstWhere('country_code', $request->filial_id);

        $clienteNombre = $cliente->nombre_cliente ?? $request->cliente_id;
        $familiaNombre = $familia->nombre_familia ?? $request->familia_id;
        $filialNombre  = $filial->nombre_local ?? $filial->country_name ?? ($request->filial_id === 'AR' ? 'Argentina' : $request->filial_id);

        $tipoInformeNombre = null;
        if ($request->filled('tipo_informe_id') && $request->genera_informes == '1') {
            $userId = \Illuminate\Support\Facades\Session::get('usuario')->user_id;
            $tipos  = SQLConnection::backendStoreProcedure('LN_tipo_informes_', array('LISTAR_FAMILIA', '', '', NULL, 1, 5, 20, $request->cliente_id, $request->familia_id, 'spa', NULL, $userId), 'select');
            $tipo   = collect($tipos)->firstWhere('idTipoInforme', $request->tipo_informe_id);
            $tipoInformeNombre = $tipo->nombre_tipo_informe ?? null;
        }

        session(['alta_masiva_config' => [
            'cliente_id'          => $request->cliente_id,
            'cliente_nombre'      => $clienteNombre,
            'familia_id'          => $request->familia_id,
            'familia_nombre'      => $familiaNombre,
            'filial_id'           => $request->filial_id,
            'filial_nombre'       => $filialNombre,
            'genera_informes'     => $request->genera_informes,
            'tipo_informe_id'     => $request->tipo_informe_id,
            'tipo_informe_nombre' => $tipoInformeNombre,
        ]]);

        return redirect()->route('operaciones-masivas.alta.paso2');
    }

    // -------------------------------------------------------
    // ALTA MASIVA — PASO 2: DESCARGA Y CARGA DE ARCHIVO
    // -------------------------------------------------------

    public function altaPaso2()
    {
        $config  = session('alta_masiva_config', []);
        $origen  = session('alta_masiva_origen', 'paso1');
        $urlAtras = $origen === 'continuar'
            ? route('operaciones-masivas.index')
            : route('operaciones-masivas.alta.paso1');

        return view('operaciones_masivas.alta.paso2_descarga_carga', compact('config', 'urlAtras'));
    }

    public function altaDescargarExcel(Request $request)
    {
        $config  = session('alta_masiva_config', []);
        $userId  = \Illuminate\Support\Facades\Session::get('usuario')->user_id;

        // Solo crear el registro si no existe ya uno (evitar duplicados si descarga varias veces)
        if (!session()->has('alta_masiva_id_config')) {
            $resultado = SQLConnection::backendStoreProcedure('OM_altas_masivas_config_', array(
                'INSERT',
                NULL,                                   // @id_config
                $userId,                                // @user_id
                $config['cliente_id']          ?? NULL, // @cliente_id
                $config['cliente_nombre']      ?? NULL, // @cliente_nombre
                $config['familia_id']          ?? NULL, // @familia_id
                $config['familia_nombre']      ?? NULL, // @familia_nombre
                $config['filial_id']           ?? NULL, // @filial_id
                $config['filial_nombre']       ?? NULL, // @filial_nombre
                $config['genera_informes']     ?? NULL, // @genera_informes
                $config['tipo_informe_id']     ?? NULL, // @tipo_informe_id
                $config['tipo_informe_nombre'] ?? NULL, // @tipo_informe_nombre
                NULL,                                   // @estado
            ), 'selectOne');

            session(['alta_masiva_id_config' => $resultado->id_config ?? null]);
        }

        // Obtener indicadores de alta para esta familia/cliente
        $indicadores = SQLConnection::backendStoreProcedure(
            'LN_indicadores_alta',
            array($config['cliente_id'], $config['familia_id']),
            'select'
        ) ?? [];
        // Generar Excel
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('Carga masiva');

        // Estilos de header
        $headerColor = '057151'; // --prod-pri
        $col = 1;

        $headers = [
            ['label' => 'CUIT (*)'],
            ['label' => 'RAZON SOCIAL'],
            ['label' => 'PAIS (*)'],
        ];
        foreach ($indicadores as $ind) {
            $label = strtoupper($ind->etiqueta ?? $ind->nombre_indicador);
            if ($ind->obligatorio == '1') $label .= ' (*)';
            $headers[] = ['label' => $label];
        }

        foreach ($headers as $h) {
            $colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
            $coord     = $colLetter . '1';
            $sheet->setCellValue($coord, $h['label']);
            $sheet->getStyle($coord)->applyFromArray([
                'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 11],
                'fill'      => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => $headerColor]],
                'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
                'borders'   => ['allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => 'FFFFFF']]],
            ]);
            $sheet->getColumnDimension($colLetter)->setWidth(22);
            $col++;
        }

        $sheet->getRowDimension(1)->setRowHeight(22);

        // Congelar la primera fila
        $sheet->freezePane('A2');

        $filename = 'alta_masiva_' . ($config['familia_nombre'] ?? 'plantilla') . '_' . date('Ymd') . '.xlsx';
        $filename = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $filename);

        $writer = new Xlsx($spreadsheet);

        return response()->streamDownload(function () use ($writer) {
            $writer->save('php://output');
        }, $filename, [
            'Content-Type'        => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'Cache-Control'       => 'max-age=0',
        ]);
    }

    public function altaCargarArchivo(Request $request)
    {
        $request->validate([
            'archivo_excel' => 'required|file|mimes:xls,xlsx',
        ]);

        $config   = session('alta_masiva_config', []);
        $idConfig = session('alta_masiva_id_config');

        // Marcar como cargado en la tabla de config (el id_carga se guarda después de generarlo)


        // Leer el Excel y cargar en staging
        $archivo = $request->file('archivo_excel');
        $reader  = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($archivo->getPathname());
        $reader->setReadDataOnly(true);
        $spreadsheet = $reader->load($archivo->getPathname());
        $sheet = $spreadsheet->getActiveSheet();
        $rows  = $sheet->toArray(null, true, true, true);

        // Fila 1 = headers, desde fila 2 = datos
        $headers = array_map('strtoupper', array_map('trim', $rows[1] ?? []));

        // Columnas obligatorias: las que tienen (*) en el header
        $colsObligatorias = array_filter($headers, fn($h) => str_contains($h, '(*)'));

        // Mapear columnas por nombre
        $colCuit        = array_search('CUIT (*)', $headers)  ?: array_search('CUIT', $headers);
        $colRazonSocial = array_search('RAZON SOCIAL', $headers);
        $colPais        = array_search('PAIS (*)', $headers)   ?: array_search('PAIS', $headers);

        // Columnas de indicadores: todas las columnas extra que no son CUIT/RAZON SOCIAL/PAIS
        $indicadoresDef = SQLConnection::backendStoreProcedure(
            'LN_indicadores_alta',
            [$config['cliente_id'], $config['familia_id']],
            'select'
        ) ?? [];

        $headerToIndicador = []; // label → [id, tipo_dato]
        foreach ($indicadoresDef as $ind) {
            $label = strtoupper($ind->etiqueta ?? $ind->nombre_indicador);
            if ($ind->obligatorio == '1') $label .= ' (*)';
            $headerToIndicador[$label] = ['id' => $ind->indicador, 'tipo_dato' => $ind->tipo_dato];
        }

        $colsIndicadores = []; // colLetter → [id, tipo_dato]
        foreach ($headers as $colLetter => $headerLabel) {
            if (isset($headerToIndicador[$headerLabel])) {
                $colsIndicadores[$colLetter] = $headerToIndicador[$headerLabel];
            }
        }

        $idCarga      = \Illuminate\Support\Str::uuid()->toString();
        $fila         = 0;
        $erroresOblig = [];
        $xmlStr       = '<filas>';
        $indicadoresPorFila = []; // fila → [[indicador_id, tipo_dato, valor]]

        foreach ($rows as $rowNum => $row) {
            if ($rowNum === 1) continue; // saltear header

            $cuit = trim($row[$colCuit] ?? '');
            if ($cuit === '') continue;  // saltear filas vacías

            $fila++;

            // Validar campos obligatorios
            foreach ($colsObligatorias as $colIdx => $headerLabel) {
                $valor = trim($row[$colIdx] ?? '');
                if ($valor === '') {
                    $erroresOblig[] = "Fila {$rowNum}: el campo \"{$headerLabel}\" es obligatorio y está vacío.";
                }
            }

            $razonSocial = $colRazonSocial ? trim($row[$colRazonSocial] ?? '') : null;
            $paisRaw     = $colPais        ? trim($row[$colPais]        ?? '') : null;
            $pais        = $paisRaw ? strtoupper(substr($paisRaw, 0, 2)) : null;

            // Capturar valores de indicadores para esta fila
            $indVals = [];
            foreach ($colsIndicadores as $colLetter => $indInfo) {
                $val = trim($row[$colLetter] ?? '');
                if ($val !== '') {
                    $indVals[] = ['indicador_id' => $indInfo['id'], 'tipo_dato' => $indInfo['tipo_dato'], 'valor' => $val];
                }
            }
            $indicadoresPorFila[$fila] = $indVals;

            $xmlStr .= '<fila>'
                . '<fila>' . $fila . '</fila>'
                . '<cuit>' . htmlspecialchars($cuit, ENT_XML1, 'UTF-8') . '</cuit>'
                . ($razonSocial ? '<razon_social>' . htmlspecialchars($razonSocial, ENT_XML1, 'UTF-8') . '</razon_social>' : '')
                . ($pais        ? '<pais>'         . htmlspecialchars($pais,        ENT_XML1, 'UTF-8') . '</pais>'         : '')
                . '</fila>';
        }

        $xmlStr .= '</filas>';

        // Si hay campos obligatorios vacíos, no insertar nada y devolver error
        if (!empty($erroresOblig)) {
            return back()->withErrors(['archivo_excel' => implode(' | ', array_slice($erroresOblig, 0, 5))])->withInput();
        }

        SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
            ['CARGAR_LOTE', $idCarga, null, null, null, null, null, $xmlStr],
            'selectOne'
        );

        // Guardar valores de indicadores en staging auxiliar
        if (!empty($indicadoresPorFila)) {
            $xmlInd = '<indicadores>';
            foreach ($indicadoresPorFila as $filaNum => $indVals) {
                foreach ($indVals as $indVal) {
                    $xmlInd .= '<ind'
                        . ' fila="'         . (int) $filaNum               . '"'
                        . ' indicador_id="' . (int) $indVal['indicador_id'] . '"'
                        . ' tipo_dato="'    . htmlspecialchars($indVal['tipo_dato'] ?? '', ENT_XML1, 'UTF-8') . '"'
                        . ' valor="'        . htmlspecialchars($indVal['valor'],       ENT_XML1, 'UTF-8') . '"'
                        . '/>';
                }
            }
            $xmlInd .= '</indicadores>';

            SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
                ['GUARDAR_INDICADORES_STAGING', $idCarga, null, null, null, null, null, $xmlInd],
                'selectOne'
            );
        }



        // Llamar al SP de validación
        $resumen = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
            ['VALIDAR', $idCarga, $config['cliente_id'] ?? null, $config['familia_id'] ?? null, $config['filial_id'] ?? null],
            'selectOne'
        );

        // Persistir id_carga y estado en la tabla para poder retomar el Paso 3
        if ($idConfig) {
            SQLConnection::backendStoreProcedure('OM_altas_masivas_config_', array(
                'UPDATE_ESTADO', $idConfig, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'cargado', $idCarga,
            ), 'selectOne');
        }

        session([
            'alta_masiva_id_carga'  => $idCarga,
            'alta_masiva_id_config' => $idConfig, // se necesita en altaConfirmar
            'alta_masiva_resumen'  => [
                'listos'                   => $resumen->listos                   ?? 0,
                'invalidos'                => $resumen->invalidos                ?? 0,
                'pais_incorrecto'          => $resumen->pais_incorrecto          ?? 0,
                'denominacion_no_coincide' => $resumen->denominacion_no_coincide ?? 0,
                'duplicados'               => $resumen->duplicados               ?? 0,
                'gestion_misma_familia'    => $resumen->gestion_misma_familia    ?? 0,
                'gestion_otra_familia'     => $resumen->gestion_otra_familia     ?? 0,
                'multiples_gestiones'      => $resumen->multiples_gestiones      ?? 0,
            ],
        ]);
        return redirect()->route('operaciones-masivas.alta.paso3');
    }

    // -------------------------------------------------------
    // ALTA MASIVA — CONTINUAR CARGA PENDIENTE
    // -------------------------------------------------------

    public function altaContinuarPendiente(Request $request)
    {
        // Si viene del modal con múltiples pendientes, recibe el id_config elegido
        $idConfig   = $request->input('id_config');
        $pendientes = $this->_pendientesDelUsuario();

        if (empty($pendientes)) {
            return redirect()->route('operaciones-masivas.index');
        }

        // Si no viene id_config (un solo pendiente), tomar el único
        if (!$idConfig && count($pendientes) === 1) {
            $idConfig = $pendientes[0]->id_config;
        }

        $registro = SQLConnection::backendStoreProcedure('OM_altas_masivas_config_', array(
            'SELECT_ONE', $idConfig, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        ), 'selectOne');

        if (!$registro) {
            return redirect()->route('operaciones-masivas.index');
        }

        // Restaurar sesión con la config guardada en la tabla
        session(['alta_masiva_origen' => 'continuar']);

        $sessionData = [
            'alta_masiva_config' => [
                'cliente_id'          => $registro->cliente_id,
                'cliente_nombre'      => $registro->cliente_nombre,
                'familia_id'          => $registro->familia_id,
                'familia_nombre'      => $registro->familia_nombre,
                'filial_id'           => $registro->filial_id,
                'filial_nombre'       => $registro->filial_nombre,
                'genera_informes'     => $registro->genera_informes,
                'tipo_informe_id'     => $registro->tipo_informe_id,
                'tipo_informe_nombre' => $registro->tipo_informe_nombre,
            ],
            'alta_masiva_id_config' => $registro->id_config,
        ];

        // Si el estado es 'cargado', restaurar también el id_carga y el resumen del staging
        if ($registro->estado === 'cargado' && !empty($registro->id_carga)) {
            $resumen = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
                ['RESUMEN', $registro->id_carga],
                'selectOne'
            );

            $sessionData['alta_masiva_id_carga'] = $registro->id_carga;
            $sessionData['alta_masiva_resumen']  = [
                'listos'                   => $resumen->listos                   ?? 0,
                'invalidos'                => $resumen->invalidos                ?? 0,
                'denominacion_no_coincide' => $resumen->denominacion_no_coincide ?? 0,
                'duplicados'               => $resumen->duplicados               ?? 0,
                'gestion_misma_familia'    => $resumen->gestion_misma_familia    ?? 0,
                'gestion_otra_familia'     => $resumen->gestion_otra_familia     ?? 0,
                'multiples_gestiones'      => $resumen->multiples_gestiones      ?? 0,
            ];
        }

        session($sessionData);

        return $registro->estado === 'cargado'
            ? redirect()->route('operaciones-masivas.alta.paso3')
            : redirect()->route('operaciones-masivas.alta.paso2');
    }

    // -------------------------------------------------------
    // ALTA MASIVA — PASO 3: REVISIÓN DE CARGA
    // -------------------------------------------------------

    public function altaPaso3()
    {
        $config  = session('alta_masiva_config', []);
        $resumen = session('alta_masiva_resumen', [
            'listos'                   => 0,
            'invalidos'                => 0,
            'denominacion_no_coincide' => 0,
            'duplicados'               => 0,
            'gestion_misma_familia'    => 0,
            'gestion_otra_familia'     => 0,
            'multiples_gestiones'      => 0,
        ]);

        return view('operaciones_masivas.alta.paso3_revision', compact('config', 'resumen'));
    }

    public function altaConfirmar(Request $request)
    {
        $config  = session('alta_masiva_config', []);
        $idCarga = session('alta_masiva_id_carga');
        $userId  = \Illuminate\Support\Facades\Session::get('usuario')->user_id;
        $familiaId      = $config['familia_id']      ?? null;
        $clienteId      = $config['cliente_id']      ?? null;
        $generaInformes = $config['genera_informes'] ?? false;
        $fechaDesde    = date('Y-m-d');
        $fechaHasta = '2099-12-31';

        // Traer los 'listo' y el primer 'duplicado' de cada CUIT
        $adar = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
            ['PARA_CONFIRMAR', $idCarga],
            'select'
        );

        foreach ($adar as $row) {
            // Si ya existe como contraparte del cliente → nueva gestión (1)
            // Si no existe → crear contraparte nueva (0)
            $nuevaGestion = $row->contraparte ? 1 : 0;

            $accion = $generaInformes ? 'alta_contraparte_v3' : 'CREAR_CONTRAPARTE';

            SQLConnection::backendStoreProcedure('LN_panel_control', [
                $accion,
                $clienteId,
                $userId,
                env('LED_PRODUCTO'),
                null,
                $row->id_padron,
                $familiaId,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                '',
                env('FILIAL_DEFAULT'),
                env('IDIOMA_DEFAULT'),
                env('DATAMANAGER_DEFAULT'),
                env('ASIGNADO_DEFAULT'),
                env('ESTADO_INFORME_INICIAL'),
                null,
                null, null, null,
                $row->contraparte ?: null,
                null, null,
                null,
                $fechaDesde,
                null,
                env('LED_PRODUCTO'),
                $nuevaGestion,
                null, null, null, null, null, null,
                null,
            ], 'selectOne');

            // Guardar indicadores del Excel en LN_contraparte_indicadores
            if ($row->id_staging) {
                if ($row->contraparte) {
                    $cpId = (int) $row->contraparte;
                } else {
                    $cpRow = SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                        ['CONTRAPARTE_POR_PADRON', null, null, null, null, null, null, $row->id_padron, $clienteId],
                        'selectOne'
                    );
                    $cpId = (int) ($cpRow->contraparte ?? 0);
                }

                if ($cpId) {
                    $gestRow = SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                        ['GESTION_VIGENTE', $cpId],
                        'selectOne'
                    );
                    $gestion = $gestRow->gestion ?? null;

                    if ($gestion) {
                        SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                            ['MIGRAR_DESDE_STAGING', $cpId, $gestion, null, null, $familiaId, $userId, null, null, $idCarga, (int) $row->id_staging],
                            'selectOne'
                        );
                    }
                }
            }
        }

        // Marcar como completado en la tabla de config
        $idConfig = session('alta_masiva_id_config');
        if ($idConfig) {
            SQLConnection::backendStoreProcedure('OM_altas_masivas_config_', array(
                'UPDATE_ESTADO', $idConfig, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'completado', NULL,
            ), 'selectOne');
        }

        // Limpiar staging
        if ($idCarga) {
            SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_', ['LIMPIAR', $idCarga], 'selectOne');
        }

        session()->forget(['alta_masiva_config', 'alta_masiva_archivo', 'alta_masiva_id_config', 'alta_masiva_id_carga', 'alta_masiva_resumen', 'alta_masiva_origen']);

        return response()->json(['status' => 'ok', 'mensaje' => 'Alta confirmada.']);
    }

    // -------------------------------------------------------
    // ALTA MASIVA — INSTANCIAS DE REVISIÓN (MODALES)
    // -------------------------------------------------------

    public function revisionMismaFamilia(Request $request)
    {
        $idCarga = session('alta_masiva_id_carga');
        $registros = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
            ['DETALLE', $idCarga, null, null, null, 'misma_familia'],
            'select'
        );

        return response()->json(collect($registros)->map(fn($r) => [
            'id'          => $r->id_staging ?? $r->fila,
            'cuit'        => $r->cuit,
            'nombre'      => $r->nombre_padron ?? $r->razon_social,
            'familia'     => $r->nombre_familia_activa,
            'fecha_inicio'=> $r->fecha_desde,
            'fecha_fin'   => $r->fecha_hasta,
            '_accion'     => '',
        ]));
    }

    public function revisionOtraFamilia(Request $request)
    {
        $idCarga = session('alta_masiva_id_carga');
        $registros = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
            ['DETALLE', $idCarga, null, null, null, 'otra_familia'],
            'select'
        );

        return response()->json(collect($registros)->map(fn($r) => [
            'id'          => $r->id_staging ?? $r->fila,
            'cuit'        => $r->cuit,
            'nombre'      => $r->nombre_padron ?? $r->razon_social,
            'familia'     => $r->nombre_familia_activa,
            'fecha_inicio'=> $r->fecha_desde,
            'fecha_fin'   => $r->fecha_hasta,
            '_accion'     => '',
        ]));
    }

    public function revisionConfirmar(Request $request)
    {
        $tipo        = $request->input('tipo');        // 'misma-familia' | 'otra-familia'
        $raw          = $request->input('resoluciones', '[]');
        $resoluciones = is_array($raw) ? $raw : (json_decode($raw, true) ?? []);
        $config      = session('alta_masiva_config', []);
        $userId      = \Illuminate\Support\Facades\Session::get('usuario')->user_id;
        $idCarga     = session('alta_masiva_id_carga');
        $familiaId      = $config['familia_id']      ?? null;
        $clienteId      = $config['cliente_id']      ?? null;
        $generaInformes = !empty($config['genera_informes']) && $config['genera_informes'] != '0';
        $tipoInformeId  = $config['tipo_informe_id'] ?? null;
        $fechaDesde  = date('Y-m-d');
        $fechaHasta  = '2099-12-31';

        $accionSP = $generaInformes ? 'alta_contraparte_v3' : 'CREAR_CONTRAPARTE';

        foreach ($resoluciones as $res) {
            $idStaging = $res['id']     ?? null;
            $accion    = $res['accion'] ?? '';

            if (!$idStaging || $accion === '' || $accion === 'No crear') continue;

            // Obtener datos de la contraparte desde staging
            $row = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
                ['STAGING_ROW', $idCarga, null, null, null, null, $idStaging],
                'selectOne'
            );

            if (!$row || !$row->contraparte) continue;

            $contraparte = (int) $row->contraparte;

            if ($accion === 'Nueva gestión') {
                // Cierra la gestión activa y crea una nueva en la familia seleccionada
                SQLConnection::backendStoreProcedure('LN_panel_control', [
                    $accionSP,
                    $clienteId,
                    $userId,
                    env('LED_PRODUCTO'),
                    $tipoInformeId, // id_tipo_informe
                    $row->id_padron,
                    $familiaId,
                    null, null,
                    null,           // nombre_contacto
                    null, null,
                    null,           // email
                    null,           // telefono
                    '',             // datos_comerciales
                    env('FILIAL_DEFAULT'),
                    env('IDIOMA_DEFAULT'),
                    env('DATAMANAGER_DEFAULT'),
                    env('ASIGNADO_DEFAULT'),
                    env('ESTADO_INFORME_INICIAL'),
                    null,
                    null, null, null,
                    $contraparte,   // contraparte existente
                    null, null,
                    null,           // team_id
                    $fechaDesde,
                    null,           // id_referencia
                    env('LED_PRODUCTO'),
                    1,              // nueva_gestion_contraparte = 1
                    null, null, null, null, null, null,
                    null,
                ], 'selectOne');

                $gestRow = SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                    ['GESTION_VIGENTE', $contraparte],
                    'selectOne'
                );
                if ($gestRow->gestion ?? null) {
                    SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                        ['MIGRAR_DESDE_STAGING', $contraparte, $gestRow->gestion, null, null, $familiaId, $userId, null, null, $idCarga, (int) $idStaging],
                        'selectOne'
                    );
                }

            } elseif ($accion === 'Duplicar') {
                // Crea una NUEVA contraparte en la familia destino para el mismo id_padron.
                // La contraparte original en su familia de origen queda intacta.
                SQLConnection::backendStoreProcedure('LN_panel_control', [
                    $accionSP,
                    $clienteId,
                    $userId,
                    env('LED_PRODUCTO'),
                    $tipoInformeId,
                    $row->id_padron,
                    $familiaId,
                    null, null,
                    null,
                    null, null,
                    null,
                    null,
                    '',
                    env('FILIAL_DEFAULT'),
                    env('IDIOMA_DEFAULT'),
                    env('DATAMANAGER_DEFAULT'),
                    env('ASIGNADO_DEFAULT'),
                    env('ESTADO_INFORME_INICIAL'),
                    null,
                    null, null, null,
                    null,   // sin contraparte existente → nueva contraparte
                    null, null,
                    null,
                    $fechaDesde,
                    null,
                    env('LED_PRODUCTO'),
                    0,      // nueva_gestion_contraparte = 0 → nueva contraparte
                    null, null, null, null, null, null,
                    null,
                ], 'selectOne');

                // Buscar la nueva contraparte recién creada para guardar sus indicadores
                $cpNuevaRow = SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                    ['CONTRAPARTE_POR_PADRON', null, null, null, null, null, null, $row->id_padron, $clienteId],
                    'selectOne'
                );
                $cpNueva = (int) ($cpNuevaRow->contraparte ?? 0);

                if ($cpNueva) {
                    $gestRow = SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                        ['GESTION_VIGENTE', $cpNueva],
                        'selectOne'
                    );
                    if ($gestRow->gestion ?? null) {
                        SQLConnection::backendStoreProcedure('OM_contraparte_indicadores_',
                            ['MIGRAR_DESDE_STAGING', $cpNueva, $gestRow->gestion, null, null, $familiaId, $userId, null, null, $idCarga, (int) $idStaging],
                            'selectOne'
                        );
                    }
                }
            }
        }

        return response()->json(['status' => 'ok']);
    }

    public function descargarDetalle(string $tipo)
    {
        $idCarga = session('alta_masiva_id_carga');
        $mapa    = [
            'invalidos'       => 'invalido',
            'pais_incorrecto' => 'pais_incorrecto',
            'denominacion'    => 'denominacion',
            'duplicados'      => 'duplicado',
            'multiples'       => 'multiples',
        ];
        $resultado = $mapa[$tipo] ?? $tipo;

        $registros = SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_',
            ['DETALLE', $idCarga, null, null, null, $resultado],
            'select'
        );

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $headers = ['CUIT', 'RAZON SOCIAL', 'PAIS', 'NOMBRE EN PADRON', 'OBSERVACION'];
        foreach ($headers as $i => $h) {
            $col = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($i + 1);
            $sheet->setCellValue($col . '1', $h);
            $sheet->getStyle($col . '1')->getFont()->setBold(true);
        }
        foreach ($registros as $i => $r) {
            $row = $i + 2;
            $sheet->setCellValue('A' . $row, $r->cuit);
            $sheet->setCellValue('B' . $row, $r->razon_social);
            $sheet->setCellValue('C' . $row, $r->pais);
            $sheet->setCellValue('D' . $row, $r->nombre_padron);
            $sheet->setCellValue('E' . $row, $r->resultado);
        }

        $writer   = new Xlsx($spreadsheet);
        $filename = 'detalle_' . $tipo . '_' . date('Ymd') . '.xlsx';

        return response()->streamDownload(function () use ($writer) {
            $writer->save('php://output');
        }, $filename, [
            'Content-Type'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'Cache-Control' => 'max-age=0',
        ]);
    }

    // -------------------------------------------------------
    // GENERACIÓN MASIVA — PASO 1: BÚSQUEDA
    // -------------------------------------------------------

    public function generacionPaso1()
    {
        $clientes = SQLConnection::backendStoreProcedure('LED_Clientes', array('SELECT', NULL, NULL, NULL, NULL, 0, env('PLATAFORMA')), 'select');
        return view('operaciones_masivas.generacion.paso1_busqueda', compact('clientes'));
    }

    public function generacionBuscar(Request $request)
    {
        $request->validate([
            'cliente_id' => 'required',
            'familia_id' => 'required',
        ]);

        $cliente  = $request->input('cliente_id');
        $familia  = $request->input('familia_id');
        $clientes = SQLConnection::backendStoreProcedure('LED_Clientes', array('SELECT', NULL, NULL, NULL, NULL, 0, env('PLATAFORMA')), 'select');

        session([
            'generacion_masiva_cliente_id' => $cliente,
            'generacion_masiva_familia_id' => $familia,
        ]);

        $lotes = collect(SQLConnection::backendStoreProcedure('OM_lotes_generacion_masiva_', array($cliente, $familia), 'select'));

        $userId    = \Illuminate\Support\Facades\Session::get('usuario')->user_id;
        $tiposRaw  = SQLConnection::backendStoreProcedure('LN_familia_tipo_informe', ['LISTAR_FAMILIA', $familia, NULL, $userId], 'select') ?? [];
        
        $tieneTipos = collect($tiposRaw)->contains(fn($t) => $t->activo == 1 && $t->activo_fam_inf == 1);

        $familiaConfig = ['sin_tipos_informe' => !$tieneTipos];

        return view('operaciones_masivas.generacion.paso1_busqueda', compact('lotes', 'familiaConfig', 'clientes'));
    }

    // -------------------------------------------------------
    // GENERACIÓN MASIVA — PASO 2: ASIGNACIÓN DE INFORMES
    // -------------------------------------------------------

    public function generacionPaso2(int $lote)
    {
        $clienteId = session('generacion_masiva_cliente_id');
        $familiaId = session('generacion_masiva_familia_id');
        $userId    = \Illuminate\Support\Facades\Session::get('usuario')->user_id;

        // $lote es YYYYMMDD → YYYY-MM-DD para el SP
        $loteStr   = str_pad($lote, 8, '0', STR_PAD_LEFT);
        $fechaLote = substr($loteStr, 0, 4) . '-' . substr($loteStr, 4, 2) . '-' . substr($loteStr, 6, 2);

        $rows = collect(SQLConnection::backendStoreProcedure(
            'LN_crear_informes_masivos',
            [$clienteId, $fechaLote, $familiaId],
            'select'
        ) ?? []);

        $contrapartes = $rows->map(function ($r, $i) {
            return (object)[
                'id'          => $r->gestion,
                'nombre'      => $r->nombre_persona,
                'cuit'        => $r->identificacion,
                'pais'            => $r->country_code,
                'contraparte'     => $r->contraparte,
                'id_padron'       => $r->id_padron,
                'gestion'         => $r->gestion,
                'id_team_default' => $r->id_team_default,
            ];
        })->values();

        $tiposRaw = SQLConnection::backendStoreProcedure(
            'LN_tipo_informes_',
            ['LISTAR_FAMILIA', '', '', NULL, 1, 5, 20, $clienteId, $familiaId, 'spa', NULL, $userId],
            'select'
        ) ?? [];

        $tiposInforme = collect($tiposRaw)->map(fn($t) => (object)[
            'id'     => $t->idTipoInforme,
            'nombre' => $t->nombre_tipo_informe,
        ]);

        return view('operaciones_masivas.generacion.paso2_asignacion',
            compact('lote', 'contrapartes', 'tiposInforme'));
    }

    public function generacionConfirmarAsignacion(Request $request)
    {
        // TODO: Calcular resumen por tipo de informe
        $resumen = [];

        return response()->json(['status' => 'ok', 'resumen' => $resumen]);
    }

    public function generacionGenerarInformes(Request $request)
    {
        $raw         = $request->input('asignaciones', '{}');
        $asignaciones = is_array($raw) ? $raw : (json_decode($raw, true) ?? []);
        $clienteId   = session('generacion_masiva_cliente_id');
        $familiaId   = session('generacion_masiva_familia_id');
        $userId      = \Illuminate\Support\Facades\Session::get('usuario')->user_id;
        $fechaHoy    = date('Y-m-d');

        if (empty($asignaciones)) {
            return response()->json(['status' => 'error', 'mensaje' => 'Sin asignaciones.'], 422);
        }

        $generados = 0;

        foreach ($asignaciones as $gestionId => $asig) {
            $tipoInformeId = $asig['tipoId'] ?? null;
            $contraparte   = $asig['contraparte'] ?? null;
            $idPadron      = $asig['idPadron'] ?? null;
            $teamDefault   = $asig['idTeamDefault'] ?? null;

            if (!$tipoInformeId || !$contraparte) continue;

            // Traer datos del tipo de informe (duracion, servicio_contratado)
            $dataInforme = SQLConnection::backendStoreProcedure(
                'LN_tipo_informes_',
                ['EDITAR', null, null, null, null, null, null, null, null, null, $tipoInformeId, null],
                'selectOne'
            );

            $fechas = \App\Custom\Misc::establecerFechasInforme($dataInforme->duracion, $fechaHoy);

            $paramsCrear = [
                'CREAR_INFORME_Y_TAREAS',
                $clienteId,
                $userId,
                //Se hardcodea producto.
                2002,
                $tipoInformeId,
                $idPadron,
                $familiaId,
                null, null, null, null, null,
                null,
                null,
                null,
                env('FILIAL_DEFAULT'),
                env('IDIOMA_DEFAULT'),
                env('DATAMANAGER_DEFAULT'),
                env('ASIGNADO_DEFAULT'),
                env('ESTADO_INFORME_INICIAL'),
                null,
                $fechas['fecha_comprometida'],
                null, null,
                $contraparte,
                null, null,
                $teamDefault,
                $fechas['fecha_inicio'],
                null,
                $dataInforme->servicio_contratado,
                0,
                null, null, null, null,
            ];

            // Crear informe y tareas
            $informe = SQLConnection::backendStoreProcedure('LN_panel_control', $paramsCrear, 'selectOne');


            $paramsDemo = [
                'CREAR_LN_DEMO',
                $clienteId,
                $userId,
                //Se hardcodea producto.
                2002,
                $tipoInformeId,
                $idPadron,
                $familiaId,
                null, null, null, null, null,
                null, null, null,
                env('FILIAL_DEFAULT'),
                env('IDIOMA_DEFAULT'),
                env('DATAMANAGER_DEFAULT'),
                env('ASIGNADO_DEFAULT'),
                env('ESTADO_INFORME_INICIAL'),
                null,
                $fechas['fecha_comprometida'],
                null, null,
                $contraparte,
                null, null,
                $teamDefault,
                $fechas['fecha_inicio'],
                null,
                $dataInforme->servicio_contratado,
                0,
                null, null, null, null,
                (int) $gestionId,
                $informe->informe,
            ];

            // Registrar en LN_demo para que no vuelva a aparecer en futuros lotes
            $resultDemo = SQLConnection::backendStoreProcedure('LN_panel_control', $paramsDemo, 'selectOne');

            $generados++;
        }

        return response()->json(['status' => 'ok', 'generados' => $generados]);
    }

    public function generacionDescargarExcel(int $lote)
    {
        // TODO: Generar y devolver Excel
        return response()->json(['status' => 'pendiente']);
    }

    // -------------------------------------------------------
    // ALTA MASIVA — CANCELAR
    // -------------------------------------------------------

    public function altaCancelar(Request $request)
    {
        $idConfig = session('alta_masiva_id_config');
        if ($idConfig) {
            SQLConnection::backendStoreProcedure('OM_altas_masivas_config_', array(
                'DELETE', $idConfig, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
            ), 'selectOne');
        }

        $idCarga = session('alta_masiva_id_carga');
        if ($idCarga) {
            SQLConnection::backendStoreProcedure('OM_validar_carga_masiva_', ['LIMPIAR', $idCarga], 'selectOne');
        }

        $origen = session('alta_masiva_origen', 'paso1');
        session()->forget(['alta_masiva_config', 'alta_masiva_archivo', 'alta_masiva_id_config', 'alta_masiva_id_carga', 'alta_masiva_resumen', 'alta_masiva_origen']);

        return $origen === 'paso1'
            ? redirect()->route('operaciones-masivas.alta.paso1')
            : redirect()->route('operaciones-masivas.index');
    }

    // -------------------------------------------------------
    // AJAX AUXILIARES
    // -------------------------------------------------------

    public function familiasPorCliente(Request $request)
    {
        $cliente = $request->input('cliente_id');
        $familias = SQLConnection::backendStoreProcedure('LN_familias_', array('search', NULL, NULL, $cliente, NULL, NULL, NULL), 'select');

        return response()->json(
            collect($familias)->map(fn($f) => ['id' => $f->familia, 'nombre' => $f->nombre_familia])->values()
        );
    }

    public function filialesPorCliente(Request $request)
    {
        $cliente = $request->input('cliente_id');
        $filiales = SQLConnection::backendStoreProcedure('backend_cliente_paises', array('obtener_cliente_paises', $cliente), 'select');

        if (empty($filiales)) {
            return response()->json([['id' => 'AR', 'nombre' => 'Argentina']]);
        }

        return response()->json(
            collect($filiales)->map(fn($f) => ['id' => $f->country_code, 'nombre' => $f->nombre_local ?? $f->country_name])->values()
        );
    }

    public function tiposInformePorFamilia(Request $request)
    {
        $cliente  = $request->input('cliente_id');
        $familia  = $request->input('familia_id');
        $tipos = SQLConnection::backendStoreProcedure(
            'LN_tipo_informes_',
            array('LISTAR_FAMILIA', '', '', NULL, 1, 5, 20, $cliente, $familia, 'spa', NULL, \Illuminate\Support\Facades\Session::get('usuario')->user_id),
            'select'
        );

        return response()->json(
            collect($tipos)->map(fn($t) => ['id' => $t->idTipoInforme, 'nombre' => $t->nombre_tipo_informe])->values()
        );
    }

    // -------------------------------------------------------
    // PRIVADOS
    // -------------------------------------------------------

    private function _pendientesDelUsuario(): array
    {
        $userId = \Illuminate\Support\Facades\Session::get('usuario')->user_id;
        $resultado = SQLConnection::backendStoreProcedure('OM_altas_masivas_config_', array(
            'SELECT_PENDIENTES', NULL, $userId, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        ), 'select');

        return $resultado ?? [];
    }

}
