<?php
// actualizar_factura.php
include 'layouts/config.php';
include 'layouts/debug.php';
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}
include 'auth.php';

header('Content-Type: application/json; charset=utf-8');
$conn->set_charset('utf8mb4');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

function handleError($errno, $errstr, $errfile, $errline)
{
    echo json_encode([
        'success' => false,
        'message' => "Error PHP: $errstr en $errfile línea $errline"
    ]);
    exit;
}
set_error_handler('handleError');

// ===================================================
// 🔐 FUNCIÓN PARA CREAR FACTURA ELECTRÓNICA AUTOMÁTICAMENTE
// ===================================================
function crearFacturaElectronica($conn, $idLiquidacion, $usuario)
{

    // 1️⃣ VERIFICAR QUE LA LIQUIDACIÓN EXISTA Y ESTÉ EN ESTADO PREFACTURA
    $stmtCheck = $conn->prepare("
        SELECT l.id, l.estado, l.estado_factura, l.id_orden_factura,
               ef.id as id_evento_existente
        FROM f_liquidacion l
        LEFT JOIN evento_factura ef ON ef.id_liquidacion = l.id
        WHERE l.id = ? 
        LIMIT 1
    ");
    $stmtCheck->bind_param("i", $idLiquidacion);
    $stmtCheck->execute();
    $result = $stmtCheck->get_result();
    $liquidacion = $result->fetch_assoc();
    $stmtCheck->close();

    if (!$liquidacion) {
        throw new Exception("La liquidación #$idLiquidacion no existe.");
    }

    if ($liquidacion['id_evento_existente']) {
        // Ya tiene factura, no hacer nada
        return null;
    }

    // Verificar que esté en estado prefactura
    if ($liquidacion['estado_factura'] !== 'prefactura' || $liquidacion['estado'] != 2) {
        throw new Exception("La liquidación #$idLiquidacion no está en estado prefactura. Estado actual: {$liquidacion['estado_factura']} - {$liquidacion['estado']}");
    }

    // 2️⃣ OBTENER DATOS DE LA LIQUIDACIÓN Y SU SEDE/IPS
    $stmtDatos = $conn->prepare("
        SELECT 
            f.id as id_liquidacion,
            f.id_orden_factura,
            f.id_empresa_convenio,
            pap.id_sede_ips,
            s.id_ips,
            s.id as id_sede,
            ips.identificacion as nit_ips,
            ips.nombre_ips,
            ips.corganismo as codigo_habilitacion,
            ips.company_id,
            ips.id as id_ips
        FROM f_liquidacion f
        INNER JOIN ordenes_fact o ON o.id_orden_factura = f.id_orden_factura
        INNER JOIN p_datos_personales dp ON o.id_paciente = dp.id
        INNER JOIN pa_paciente pap ON pap.id_datos_personales = dp.id
        LEFT JOIN ips_sede s ON s.id = pap.id_sede_ips
        LEFT JOIN ips ON ips.id = s.id_ips
        WHERE f.id = ?
        LIMIT 1
    ");
    $stmtDatos->bind_param("i", $idLiquidacion);
    $stmtDatos->execute();
    $datos = $stmtDatos->get_result()->fetch_assoc();
    $stmtDatos->close();

    if (!$datos) {
        throw new Exception("No se encontraron datos para liquidación #$idLiquidacion.");
    }

    if (!$datos['id_sede_ips'] || !$datos['id_ips']) {
        throw new Exception("La liquidación #$idLiquidacion no tiene sede o IPS asociada.");
    }

    $idSede = (int)$datos['id_sede'];
    $idIPS = (int)$datos['id_ips'];
    $companyId = $datos['company_id'] ?? null;

    // 3️⃣ OBTENER RESOLUCIÓN ACTIVA CON BLOQUEO
    $stmtResol = $conn->prepare("
        SELECT id, prefijo, numero_actual, numero_final, clave_tecnica
        FROM d_resolucion_dian
        WHERE estado = 1
          AND id_sede = ?
          AND clasificacion = 1  -- 1 = Factura electrónica
          AND fecha_inicial <= CURDATE()
          AND fecha_final >= CURDATE()
        FOR UPDATE
    ");
    $stmtResol->bind_param("i", $idSede);
    $stmtResol->execute();
    $resResol = $stmtResol->get_result();

    if ($resResol->num_rows === 0) {
        throw new Exception("No hay resolución DIAN activa para sede ID $idSede.");
    }

    $res = $resResol->fetch_assoc();
    $stmtResol->close();

    $idResolucion = (int)$res['id'];
    $prefijo = $res['prefijo'];
    $numeroActual = (int)$res['numero_actual'];
    $numeroFinal = (int)$res['numero_final'];

    $siguiente = $numeroActual + 1;

    if ($siguiente > $numeroFinal) {
        throw new Exception("La resolución de la sede $idSede alcanzó su límite.");
    }

    // 4️⃣ INSERTAR EN evento_factura
    $stmtInsert = $conn->prepare("
        INSERT INTO evento_factura (
            id_liquidacion,
            id_resolucion_dian,
            prefijo,
            numero_factura,
            tipo_factura,
            estado,
            estado_dian,
            usuario_crea,
            id_sede,
            id_ips,
            company_id,
            health_type_operation_id
        ) VALUES (?, ?, ?, ?, 'electronica', 'activa', 'PENDIENTE', ?, ?, ?, ?, 7)
    ");

    $stmtInsert->bind_param(
        "iisissii",
        $idLiquidacion,
        $idResolucion,
        $prefijo,
        $siguiente,
        $usuario,
        $idSede,
        $idIPS,
        $companyId
    );

    $stmtInsert->execute();
    $idEvento = $stmtInsert->insert_id;
    $stmtInsert->close();

    // 5️⃣ ACTUALIZAR CONSECUTIVO EN RESOLUCIÓN
    $stmtUpdateResol = $conn->prepare("
        UPDATE d_resolucion_dian
        SET numero_actual = ?
        WHERE id = ?
    ");
    $stmtUpdateResol->bind_param("ii", $siguiente, $idResolucion);
    $stmtUpdateResol->execute();
    $stmtUpdateResol->close();

    // 6️⃣ ACTUALIZAR LIQUIDACIÓN
    $stmtUpdateLiq = $conn->prepare("
        UPDATE f_liquidacion
        SET id_evento_factura = ?,
            estado = 3,  -- 3 = facturado
            estado_factura = 'facturada',
            created_at = NOW()
        WHERE id = ?
    ");
    $stmtUpdateLiq->bind_param("ii", $idEvento, $idLiquidacion);
    $stmtUpdateLiq->execute();
    $stmtUpdateLiq->close();

    return [
        'id_evento' => $idEvento,
        'factura' => $prefijo . $siguiente,
        'id_sede' => $idSede,
        'id_ips' => $idIPS
    ];
}


// ===================================================
// 🔐 FUNCIONES DE VALIDACIÓN DE AUTORIZACIÓN
// ===================================================

function validarAutorizacionDuplicada($conn, $autorizacion, $idPaciente = null, $idFacturaExcluir = null)
{
    if (empty($autorizacion) || $autorizacion === 'OMITIDA' || $autorizacion === 'idTipoDiscapacidad') {
        return ['valida' => true, 'duplicada' => false];
    }

    // Usar transacción con lock para evitar race conditions
    $conn->begin_transaction();

    try {
        // Verificar en TODAS las tablas relevantes
        $sql = "
            SELECT 
                'orden_fact' as tabla_origen,
                of.id_orden_factura as id,
                of.fecha_orden as fecha,
                CONCAT(pdp.nombre1, ' ', pdp.apellido1) as paciente,
                of.estado
            FROM ordenes_fact of
            JOIN p_datos_personales pdp ON of.id_paciente = pdp.id
            WHERE of.autorizacion_fact = ?
            AND of.estado = 1  -- Solo órdenes activas
            
            UNION ALL
            
            SELECT 
                'cita' as tabla_origen,
                cp.id as id,
                cp.fecha_ingreso as fecha,
                CONCAT(pdp.nombre1, ' ', pdp.apellido1) as paciente,
                cp.estado_cita as estado
            FROM c_cita_programada cp
            JOIN p_datos_personales pdp ON cp.id_datos_personales = pdp.id
            WHERE cp.no_autorizacion = ?
            AND cp.estado_cita != 'Anulada'
          
            FOR UPDATE  -- Lock pesimista
        ";

        $stmt = $conn->prepare($sql);
        $stmt->bind_param("ss", $autorizacion, $autorizacion);
        $stmt->execute();
        $result = $stmt->get_result();

        if ($row = $result->fetch_assoc()) {
            // Si encontramos duplicado, hacemos rollback
            $conn->rollback();
            return [
                'valida' => false,
                'duplicada' => true,
                'tabla' => $row['tabla_origen'],
                'id' => $row['id'],
                'fecha' => $row['fecha'],
                'paciente' => $row['paciente'],
                'estado' => $row['estado']
            ];
        }

        // Si no hay duplicados, liberamos el lock
        $conn->commit();
        return ['valida' => true, 'duplicada' => false];
    } catch (Exception $e) {
        $conn->rollback();
        throw $e;
    }
}
function crearOrdenesMedicasFueraTransaccion($conn, $idCita, $idPaciente, $idAtencion, $fechaP, $horaP, $procedimientos, $idFinalidadGlobal, $idGrupoGlobal, $idServicioGlobal, $usuario)
{
    $resultado = ['creadas' => 0, 'errores' => []];
    
    $stmtIns = $conn->prepare("
        INSERT INTO h_ordenes_medicas_ambulatorias (
            id_cita, id_paciente, id_atencion,
            fecha_p, hora_p,
            procedimiento, cantidad_p,
            origen, realizado, observacion_proc,
            estado_procedimientos,
            id_finalidad, id_grupo, id_servicio_rips,
            activo, usuario_crea
        ) VALUES (
            ?, ?, ?,
            ?, ?,
            ?, ?,
            'interna', '0', ?,
            'completada',
            ?, ?, ?,
            1, ?
        )
    ");

    if (!$stmtIns) {
        $resultado['errores'][] = "Error preparando INSERT: " . $conn->error;
        return $resultado;
    }

    foreach ($procedimientos as $proc) {
        $idProc   = (int)($proc['id_procedimiento']       ?? 0);
        $cantidad = (int)($proc['cantidad']                ?? 1);
        $obs      = $proc['observacion']                   ?? '';
        $idFin    = $proc['id_finalidad']                  ?? $idFinalidadGlobal;
        $idGrp    = (int)($proc['id_grupo_servicio_rips']  ?? $idGrupoGlobal);
        $idSrv    = (int)($proc['id_servicio_rips']        ?? $idServicioGlobal);

        if ($idProc <= 0) {
            $resultado['errores'][] = "ID procedimiento inválido";
            continue;
        }

        $stmtIns->bind_param(
            "iiissiissiis",
            $idCita,
            $idPaciente,
            $idAtencion,
            $fechaP,
            $horaP,
            $idProc,
            $cantidad,
            $obs,
            $idFin,
            $idGrp,
            $idSrv,
            $usuario
        );

        if ($stmtIns->execute()) {
            $resultado['creadas']++;
            if ($resultado['creadas'] === 1) {
                $resultado['id_orden_medica'] = $stmtIns->insert_id;
            }
        } else {
            $resultado['errores'][] = "proc $idProc: " . $stmtIns->error;
        }
    }

    $stmtIns->close();
    return $resultado;
}


try {
    $input = json_decode(file_get_contents("php://input"), true);

    if (!$input) {
        throw new Exception('Datos no válidos: ' . json_last_error_msg());
    }
$input['hora_ingreso'] = normalizarHora($input['hora_ingreso'] ?? null, date('H:i:s'));
$input['hora_egreso']  = normalizarHora($input['hora_egreso'] ?? null, date('H:i:s'));
    error_log("📥 Datos recibidos: " . print_r($input, true));

    // ===================================================
    // 🔐 VALIDACIÓN DE AUTORIZACIÓN MEJORADA
    // ===================================================
    $autorizacion = $input['no_autorizacion'] ?? '';
    $omitirAutorizacion = $input['omitir_autorizacion'] ?? false;

    if (!$omitirAutorizacion && !empty($autorizacion) && $autorizacion !== 'OMITIDA' && $autorizacion !== 'idTipoDiscapacidad') {

        // Iniciar transacción para la validación con lock
        $conn->begin_transaction();

        try {
            $validacion = validarAutorizacionDuplicada($conn, $autorizacion, $input['id_datos_personales']);

            if (!$validacion['valida']) {
                $conn->rollback(); // Liberar locks
                throw new Exception(
                    "❌ AUTORIZACIÓN DUPLICADA: La autorización '$autorizacion' ya fue utilizada en " .
                        strtoupper($validacion['tabla']) . " #{$validacion['id']} " .
                        "del paciente {$validacion['paciente']} el {$validacion['fecha']} " .
                        "(Estado: {$validacion['estado']})."
                );
            }

            // Si es válida, continuamos con la misma transacción
            // No hacer commit aquí, se hará al final

            error_log("✅ Autorización '$autorizacion' válida - continuando con transacción principal");
        } catch (Exception $e) {
            if ($conn->ping()) {
                $conn->rollback();
            }
            throw $e;
        }
    }
    // ===================================================
    // 🚀 INICIAR TRANSACCIÓN
    // ===================================================
    $conn->begin_transaction();

    $usuario = $_SESSION['usuario'] ?? 'sistema';
    $fechaActual = date('Y-m-d');
    $horaActual = normalizarHora(date('H:i:s'), '00:00:00');
    // Validaciones previas
    if (empty($input['id_datos_personales'])) {
        throw new Exception('Falta ID del paciente');
    }
    if (empty($input['procedimientos']) || !is_array($input['procedimientos'])) {
        throw new Exception('No hay procedimientos para facturar');
    }

    // ===================================================
    // 🏥 1. CREAR CITA PROGRAMADA
    // ===================================================
    // Obtener el primer procedimiento correctamente
    $primerProcedimiento = reset($input['procedimientos']);

    $sqlCita = "
        INSERT INTO c_cita_programada (
            no_documento,
            id_datos_personales,
            id_profesional,
            id_eps,
            id_tipoafiliado,
            id_especialidad,
            id_procedimiento,
            id_finalidad,
            id_grupo,
            id_servicio_rips,
            id_tipo_atencion,
            no_autorizacion,
            id_causa_externa,
            id_clase_cita,
            empresa_eps_convenio,
            estrato,
            contrato,
            id_contratacion,
            id_cobertura,
            fecha_ingreso,
            hora_ingreso,
            cantidad,
            id_patologia,
            estado_cita,
            activo,
            usuario_crea,
            valor_copago,
            idModalidad,
            idEntornoAtencion,
            id_aseguramiento,
            facturar,
            id_ubicacion_hospitalaria,
            via_cita,
            duracion,
            copago_estado,
            id_copago,
            copago
        ) VALUES (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 
            'Facturada', 'Activa', ?, ?, ?, ?, ?, 1, 1, 0, '30', 'pendiente', ?, ?
        )
    ";

    $stmtCita = $conn->prepare($sqlCita);
    if (!$stmtCita) {
        throw new Exception('Error preparando cita: ' . $conn->error);
    }

    $noDocumento = $input['no_documento'] ?? '';
    $idCausaExterna = 13;
    $idClaseCita = 1;
    $idContrato = !empty($input['contrato']) ? (int)$input['contrato'] : null;
    $idContratacion = $input['id_contratacion'] ?? null;
    $idUbicacionHospitalaria = null;
    $viaCita = 1;
    $duracion = '40';
    $copagoEstado = 'pendiente';
    $idCopago = intval($input['id_copago'] ?? 0);
    $copago = intval($input['valor_copago'] ?? 0) > 0 ? 1 : 0;

    // CORRECCIÓN: Usar los valores del primer procedimiento
    $id_finalidad = $primerProcedimiento['id_finalidad'] ?? null;
    $id_grupo_servicio_rips = $primerProcedimiento['id_grupo_servicio_rips'] ?? null;
    $id_servicio_rips = $primerProcedimiento['id_servicio_rips'] ?? 1;

    $id_cobertura = $input['id_cobertura'] ?? null;
    $id_patologia = $input['id_patologia'] ?? null;
    $id_estrato = $input['id_estrato'] ?? 1;
    $valor_copago = floatval($input['valor_copago'] ?? 0);
    $idModalidad = $input['idModalidad'] ?? 1;
    $idEntornoAtencion = $input['idEntornoAtencion'] ?? 5;
    $id_aseguramiento = $input['id_aseguramiento'] ?? 1;
    $fecha_ingreso = $input['fecha_ingreso'] ?? $fechaActual;
    $hora_ingreso = normalizarHora($input['hora_ingreso'] ?? $horaActual, $horaActual);
    // CORRECCIÓN: El string de tipos debe coincidir exactamente con el número de parámetros
    $stmtCita->bind_param(
        "siiiiiiiiiisiiiiiiississdiiiis",
        $noDocumento,
        $input['id_datos_personales'],
        $input['id_profesional'],
        $input['id_eps'],
        $input['id_tipoafiliado'],
        $input['id_especialidad'],
        $primerProcedimiento['id_procedimiento'],
        $id_finalidad,
        $id_grupo_servicio_rips,
        $id_servicio_rips,
        $input['id_tipo_atencion'],
        $autorizacion,
        $idCausaExterna,
        $idClaseCita,
        $input['empresa_eps_convenio'],
        $id_estrato,
        $idContrato,
        $idContratacion,
        $id_cobertura,
        $fecha_ingreso,
        $hora_ingreso,
        $primerProcedimiento['cantidad'],
        $id_patologia,
        $usuario,
        $valor_copago,
        $idModalidad,
        $idEntornoAtencion,
        $id_aseguramiento,
        $idCopago,
        $copago
    );

    if (!$stmtCita->execute()) {
        throw new Exception('Error al crear cita: ' . $stmtCita->error);
    }

    $idCita = $stmtCita->insert_id;
    error_log("✅ Cita creada: ID " . $idCita);
    $stmtCita->close();

    // ===================================================
    // 🏥 2. CREAR ATENCIÓN MÉDICA
    // ===================================================
    $sqlAtencion = "
        INSERT INTO h_atencion_medicas (
            id_paciente,
            id_cita,
            motivo_atencion,
            enfermedad_actual,
            tiempo_evolucion,
            unidad_tiempo,
            intensidad_dolor,
            factores_desencadenantes,
            curso_enfermedad,
            tratamientos_previos,
            otros_sintomas,
            fecha_atencion,
            hora_atencion,
            tipo,
            permite_nuevas_atenciones,
            activo,
            usuario_crea
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'inicial', 0, 1, ?)
    ";

    $stmtAtencion = $conn->prepare($sqlAtencion);
    if (!$stmtAtencion) {
        throw new Exception('Error preparando atención: ' . $conn->error);
    }

    $motivoAtencion = 'Atención médica programada';
    $enfermedadActual = 'Consulta de control';
    $tiempoEvolucion = null;
    $unidadTiempo = null;
    $intensidadDolor = null;
    $factoresDesencadenantes = null;
    $cursoEnfermedad = null;
    $tratamientosPrevios = null;
    $otrosSintomas = null;

    $fechaAtencion = $input['fecha_ingreso'] ?? $fechaActual;
    $horaAtencion = normalizarHora($input['hora_ingreso'] ?? $horaActual, $horaActual);
        if (strlen($horaAtencion) == 5) $horaAtencion .= ':00';

    $stmtAtencion->bind_param(
        "iissssisssssss",
        $input['id_datos_personales'],
        $idCita,
        $motivoAtencion,
        $enfermedadActual,
        $tiempoEvolucion,
        $unidadTiempo,
        $intensidadDolor,
        $factoresDesencadenantes,
        $cursoEnfermedad,
        $tratamientosPrevios,
        $otrosSintomas,
        $fechaAtencion,
        $horaAtencion,
        $usuario
    );

    if (!$stmtAtencion->execute()) {
        throw new Exception('Error al crear atención: ' . $stmtAtencion->error);
    }

    $idAtencion = $stmtAtencion->insert_id;
    error_log("✅ Atención creada: ID " . $idAtencion);
    $stmtAtencion->close();

    // ===================================================
    // 📋 3. CREAR ÓRDENES MÉDICAS
    // ===================================================
    $idOrdenMedica = null;
    $contadorOrdenes = 0;
    if (!isset($input['procedimientos']) || !is_array($input['procedimientos']) || count($input['procedimientos']) === 0) {
        throw new Exception("Error Crítico: No se recibieron procedimientos para generar la orden médica.");
    }
    foreach ($input['procedimientos'] as $index => $proc) {
        $procID = $proc['id_procedimiento'] ?? null;
        $procCant = $proc['cantidad'] ?? null;

        if (empty($procID) || empty($procCant)) {
            throw new Exception("Error en procedimiento índice $index: ID o cantidad están vacíos.");
        }

        $sqlOrdenMedica = "
            INSERT INTO h_ordenes_medicas_ambulatorias (
                id_cita,
                id_paciente,
                id_atencion,
                fecha_p,
                hora_p,
                procedimiento,
                cantidad_p,
                origen,
                realizado,
                observacion_proc,
                estado_procedimientos,
                id_finalidad,
                id_grupo,
                id_servicio_rips,
                activo,
                usuario_crea
            ) VALUES (?, ?, ?, ?, ?, ?, ?, 'interna', '0', ?, 'completada', ?, ?, ?, 1, ?)
        ";

        $stmtOrdenMedica = $conn->prepare($sqlOrdenMedica);
        if (!$stmtOrdenMedica) {
            throw new Exception('Error preparando orden médica: ' . $conn->error);
        }

        $observacion = $proc['observacion'] ?? '';
        $id_finalidad_proc = $proc['id_finalidad'] ?? $id_finalidad; // Priorizar el del proc
        $id_grupo_proc = $proc['id_grupo_servicio_rips'] ?? $id_grupo_servicio_rips;
        $id_servicio_proc = $proc['id_servicio_rips'] ?? $id_servicio_rips;

        $stmtOrdenMedica->bind_param(
            "iiississsiis",
            $idCita,
            $input['id_datos_personales'],
            $idAtencion,
            $fecha_ingreso,
            $hora_ingreso,
            $observacion,
            $procCant,
            $observacion,
            $id_finalidad,
            $id_grupo_servicio_rips,
            $$id_servicio_proc,
            $usuario
        );

        if (!$stmtOrdenMedica->execute()) {
            throw new Exception("Error al insertar orden médica ($procID): " . $stmtOrdenMedica->error);
        }

        $insertedId = $stmtOrdenMedica->insert_id;
        
        if ($index === 0) {
            $idOrdenMedica = $insertedId;
        }

        if ($insertedId > 0) {
            $contadorOrdenes++;
        }

        $stmtOrdenMedica->close();
    }
    if (empty($idOrdenMedica) || $idOrdenMedica <= 0 || $contadorOrdenes === 0) {
        throw new Exception("Error de Integridad: El proceso de creación de órdenes médicas falló. No se puede proceder con la facturación DIAN.");
    }

    error_log("✅ Se crearon $contadorOrdenes registros en h_ordenes_medicas_ambulatorias. ID de referencia: $idOrdenMedica");
    // ===================================================
    // 💰 4. CREAR EGRESO
    // ===================================================
    if (!empty($input['fecha_egreso'])) {
        $fechaEgreso = $input['fecha_egreso'];
        $horaEgreso = normalizarHora($input['hora_egreso'] ?? $horaActual, $horaActual);
                if (strlen($horaEgreso) == 5) $horaEgreso .= ':00';

        $sqlEgreso = "
            INSERT INTO h_egreso_historia (
                id_paciente,
                id_cita,
                id_atencion,
                id_profesional,
                fecha_egreso,
                hora_egreso,
                patologia_egreso,
                cie_10,
                destino_egreso,
                tipo_atencion,
                especialidad,
                recomendaciones,
                estado_egreso,
                activo,
                usuario_crea
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
        ";

        $stmtEgreso = $conn->prepare($sqlEgreso);
        if (!$stmtEgreso) {
            throw new Exception('Error preparando egreso: ' . $conn->error);
        }

        $patologiaEgreso = $input['id_patologia'] ?? '';
        $cie10 = $input['id_patologia'] ?? '';
        $destinoEgreso = 'Casa';
        $tipoAtencion = $input['id_tipo_atencion'] ?? '';
        $especialidad = '';
        $recomendaciones = null;
        $estadoEgreso = 'Mejorado';

        $stmtEgreso->bind_param(
            "iiiissssssssss",
            $input['id_datos_personales'],
            $idCita,
            $idAtencion,
            $input['id_profesional'],
            $fechaEgreso,
            $horaEgreso,
            $patologiaEgreso,
            $cie10,
            $destinoEgreso,
            $tipoAtencion,
            $especialidad,
            $recomendaciones,
            $estadoEgreso,
            $usuario
        );

        if (!$stmtEgreso->execute()) {
            throw new Exception('Error al crear egreso: ' . $stmtEgreso->error);
        }

        error_log("✅ Egreso creado: ID " . $stmtEgreso->insert_id);
        $stmtEgreso->close();
    }

    // ===================================================
// 💰 5. CALCULAR TOTALES
// ===================================================
$totalOrden = 0;
$idConvenioCita = intval($input['empresa_eps_convenio'] ?? 0);

foreach ($input['procedimientos'] as &$proc) {
    $vTotalProc = floatval($proc['valor_total'] ?? 0);
    
    // Si el valor total viene en 0, resolvemos la tarifa directamente desde el convenio
    if ($vTotalProc <= 0 && $idConvenioCita > 0) {
        $idProcTmp = intval($proc['id_procedimiento'] ?? 0);
        $stmtTarifa = $conn->prepare("SELECT Valor FROM e_procedimiento_convenio WHERE id_procedimiento = ? AND id_empresa_eps_convenio = ? AND activo = 1 LIMIT 1");
        $stmtTarifa->bind_param("ii", $idProcTmp, $idConvenioCita);
        $stmtTarifa->execute();
        $resTarifa = $stmtTarifa->get_result()->fetch_assoc();
        $stmtTarifa->close();
        
        $tarifaUnitaria = floatval($resTarifa['Valor'] ?? 0);
        $proc['valor_unitario'] = $tarifaUnitaria;
        $proc['valor_total'] = $tarifaUnitaria * intval($proc['cantidad'] ?? 1);
    }
    $totalOrden += floatval($proc['valor_total'] ?? 0);
}
unset($proc); // Romper referencia

// Identificar qué tipo de cobro al paciente se está realizando
$idTipoCopago = intval($input['id_copago'] ?? 0); 
$montoPaciente = floatval($input['valor_copago'] ?? 0);

$valorCopago = 0;
$valorModerada = 0;

if ($idTipoCopago === 1) {
    $valorCopago = $montoPaciente;
} else {
    $valorModerada = $montoPaciente;
}

$totalPaciente = $montoPaciente;
$totalEPS = $totalOrden - $totalPaciente;
$totalDescuento = 0;
// ===================================================
// 💰 6. REGISTRAR PAGO DEL PACIENTE (copago_pagos)
// ===================================================
if ($totalPaciente > 0) {
    $sqlPagos = "
        INSERT INTO copago_pagos (
            id_cita, id_paciente, id_copago, valor,
            forma_pago_id, created_at, created_by, estado
        ) VALUES (?, ?, ?, ?, ?, ?, ?, 1)
    ";
    $stmtPagos = $conn->prepare($sqlPagos);
    $fechaPago = $input['fecha_ingreso'] ?? $fechaActual;
    
    // Aquí usamos el id_copago original del input (0 o 1)
    $stmtPagos->bind_param("iiiidss", 
        $idCita, 
        $input['id_datos_personales'], 
        $idTipoCopago, 
        $totalPaciente,
        $input['id_metodo_pago'], 
        $fechaPago, 
        $usuario
    );
    
    if (!$stmtPagos->execute()) {
        throw new Exception('Error al registrar pago en copago_pagos: ' . $stmtPagos->error);
    }
    $stmtPagos->close();
}
    
    $sqlOrdenFact = "
    INSERT INTO ordenes_fact (
        id_paciente, id_orden_medica, id_servicio, id_tipoafiliado,
        id_empresa_eps, id_tipo_atencion, id_profesional, id_especialidad,
        id_centro_costo, autorizacion_fact, id_empresa_eps_convenio,
        id_cobertura, id_contratacion, id_estrato, id_contrato,
        valor_moderada, valor_copago, total_orden, total_eps,
        total_descuento, total_paciente, fecha_orden, hora_orden,
        estado, observacion, usuario_crea, id_metodo_pago, profesional_atencion
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)
";

$stmtOrdenFact = $conn->prepare($sqlOrdenFact);
if (!$stmtOrdenFact) throw new Exception('Error preparando orden facturación: ' . $conn->error);

$idCentroCosto = intval($input['id_centro_costo'] ?? 1);
$idMetodoPago = intval($input['id_metodo_pago'] ?? 10);
$profesionalAtencion = intval($input['id_profesional']);
$observacion = $input['observacion'] ?? '';
$idContrato = $input['contrato'] ?? null;

$stmtOrdenFact->bind_param(
    "iiiiiiiiisiiiiiddddddssssii",
    $input['id_datos_personales'], $idOrdenMedica, $input['id_servicios'],
    $input['id_tipoafiliado'], $input['id_eps'], $input['id_tipo_atencion'],
    $input['id_profesional'], $input['id_especialidad'], $idCentroCosto,
    $autorizacion, $input['empresa_eps_convenio'], $id_cobertura,
    $input['id_contratacion'], $input['id_estrato'], $idContrato,
    $valorModerada, $valorCopago, $totalOrden, $totalEPS,
    $totalDescuento, $totalPaciente, $fecha_ingreso, $hora_ingreso,
    $observacion, $usuario, $idMetodoPago, $profesionalAtencion
);

if (!$stmtOrdenFact->execute()) throw new Exception('Error al crear orden facturación: ' . $stmtOrdenFact->error);

$idOrdenFactura = $stmtOrdenFact->insert_id;
$stmtOrdenFact->close();

// ===================================================
// 📝 7. CREAR DETALLES RESUMEN + DETALLE UNITARIO
// ===================================================
$sqlDetalle = "
INSERT INTO f_ordenes_detalle (
    id_ordenes,
    id_procedimiento,
    codigo_procedimiento,
    id_tipo_fin_procedimiento,
    cantidad,
    valor_unitario,
    valor_total,
    ejecutado,
    estado,
    fecha,
    usuario_crea,
    id_modalidad_atencion,
    id_servicio_rips,
    id_grupo_servicio_rips,
    id_tecnologia_salud,
    descuento,
    hora_orden,
    fecha_orden
) VALUES (?, ?, ?, ?, ?, ?, ?, 1, 1, NOW(), ?, ?, ?, ?, ?, 0, ?, ?)
";

$stmtDetalle = $conn->prepare($sqlDetalle);
if (!$stmtDetalle) {
    throw new Exception('Error preparando detalle: ' . $conn->error);
}

$sqlDetUnit = "
INSERT INTO f_ordenes_detalle_ejecucion (
    id_orden_factura,
    id_orden_detalle,
    id_cita,
    id_atencion,
    id_paciente,
    id_procedimiento,
    codigo_procedimiento,
    fecha_ejecucion,
    hora_ejecucion,
    cantidad_unitaria,
    valor_unitario,
    valor_total,
    id_tipo_fin_procedimiento,
    id_modalidad_atencion,
    id_servicio_rips,
    id_grupo_servicio_rips,
    id_tecnologia_salud,
    num_autorizacion,
    cod_diagnostico_principal,
    estado,
    usuario_crea
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
";

$stmtDetUnit = $conn->prepare($sqlDetUnit);
if (!$stmtDetUnit) {
    throw new Exception('Error preparando detalle unitario: ' . $conn->error);
}

foreach ($input['procedimientos'] as $proc) {
    $sqlProc = "SELECT codigo_cups, codigo_personalizado FROM p_procedimiento WHERE id = ?";
    $stmtProc = $conn->prepare($sqlProc);

    if (!$stmtProc) {
        throw new Exception('Error preparando consulta procedimiento: ' . $conn->error);
    }

    $idProcedimiento = (int)($proc['id_procedimiento'] ?? 0);
    if ($idProcedimiento <= 0) {
        throw new Exception('ID de procedimiento inválido.');
    }

    $stmtProc->bind_param("i", $idProcedimiento);
    $stmtProc->execute();
    $rowProc = $stmtProc->get_result()->fetch_assoc();
    $stmtProc->close();

    $codigo = $rowProc['codigo_cups'] ?? $rowProc['codigo_personalizado'] ?? (string)$idProcedimiento;
    $idTipoFin = (string)($proc['id_finalidad'] ?? '1');
    $idServicioRips = (int)($proc['id_servicio_rips'] ?? 1);
    $idGrupoServicioRips = (int)($proc['id_grupo_servicio_rips'] ?? 1);
    $idModalidad = (int)($input['idModalidad'] ?? 1);
    $idTecnologiaSalud = 1;

    $cantidad = (int)($proc['cantidad'] ?? 0);
    $valorTotalProc = (float)($proc['valor_total'] ?? 0);
    $valorUnitarioProc = (float)($proc['valor_unitario'] ?? 0);

    if ($cantidad <= 0) {
        throw new Exception("La cantidad del procedimiento {$idProcedimiento} debe ser mayor que cero.");
    }

    if ($valorTotalProc <= 0) {
        throw new Exception("El valor total del procedimiento {$idProcedimiento} debe ser mayor que cero.");
    }

    if ($valorUnitarioProc <= 0) {
        $valorUnitarioProc = round($valorTotalProc / $cantidad, 2);
    }

    // 7.1 Guardar resumen administrativo
    $stmtDetalle->bind_param(
        "iissiddsiiiiss",
        $idOrdenFactura,         // i
        $idProcedimiento,        // i
        $codigo,                 // s
        $idTipoFin,              // s
        $cantidad,               // i
        $valorUnitarioProc,      // d
        $valorTotalProc,         // d
        $usuario,                // s
        $idModalidad,            // i
        $idServicioRips,         // i
        $idGrupoServicioRips,    // i
        $idTecnologiaSalud,      // i
        $hora_ingreso,           // s
        $fecha_ingreso           // s
    );

    if (!$stmtDetalle->execute()) {
        throw new Exception('Error al guardar detalle: ' . $stmtDetalle->error);
    }

    $idOrdenDetalle = (int)$stmtDetalle->insert_id;

   
    $periodoInicio = $input['fecha_ingreso'] ?? $fechaActual;
    $periodoFin = $input['fecha_egreso'] ?? $fechaActual;
    $cantidad = $primerProcedimiento['cantidad'];
    $valorTotalProc =  $valorTotalProc = (float)($proc['valor_total'] ?? 0);


    // 7.2 Distribuir fechas dentro del período
    $fechasDistribuidas = distribuirFechasEnPeriodo($periodoInicio, $periodoFin, $cantidad);

    // 7.3 Distribuir valores unitarios sin descuadrar centavos
    $valoresDistribuidos = distribuirValoresUnitarios($valorTotalProc, $cantidad);

    // 7.4 Guardar ejecuciones unitarias
    for ($i = 0; $i < $cantidad; $i++) {
        $fechaEjecucionUnit = $fechasDistribuidas[$i];
        $horaEjecucionUnit = normalizarHora($hora_ingreso, '08:00:00');
        $valorUnitarioUnit = (float)$valoresDistribuidos[$i];
        $valorTotalUnit = $valorUnitarioUnit;
        $codDiagnosticoPrincipal = !empty($id_patologia) ? (string)$id_patologia : null;

        $idPaciente = (int)$input['id_datos_personales'];

        $stmtDetUnit->bind_param(
            "iiiiiisssddsiiiisss",
            $idOrdenFactura,          // i
            $idOrdenDetalle,          // i
            $idCita,                  // i
            $idAtencion,              // i
            $idPaciente,              // i
            $idProcedimiento,         // i
            $codigo,                  // s
            $fechaEjecucionUnit,      // s
            $horaEjecucionUnit,       // s
            $valorUnitarioUnit,       // d
            $valorTotalUnit,          // d
            $idTipoFin,               // s
            $idModalidad,             // i
            $idServicioRips,          // i
            $idGrupoServicioRips,     // i
            $idTecnologiaSalud,       // i
            $autorizacion,         // s
            $codDiagnosticoPrincipal, // s
            $usuario                  // s
        );

        if (!$stmtDetUnit->execute()) {
            throw new Exception('Error al guardar detalle unitario: ' . $stmtDetUnit->error);
        }
    }
}

$stmtDetalle->close();
$stmtDetUnit->close();

error_log("✅ Detalles resumen y unitarios creados");
    // ===================================================
    // 💰 9. CREAR LIQUIDACIÓN
    // ===================================================
    $idSubgrupoServicio = 1;
    foreach ($input['procedimientos'] as $proc) {
        if (!empty($proc['id_grupo_servicio_rips'])) {
            $idSubgrupoServicio = intval($proc['id_grupo_servicio_rips']);
            break;
        }
    }
    $periodoInicio = $input['fecha_ingreso'] ?? $fechaActual;
    $periodoFin = $input['fecha_egreso'] ?? $periodoInicio;

    $sqlLiquidacion = "
        INSERT INTO f_liquidacion (
            id_orden_factura,
            total_servicio,
            total_eps,
            total_paciente,
            total_plan,
            copago,
            cuota_moderadora,
            total_descuento,
            t_glosa,
            v_glosa_r,
            v_glosa_nr,
            t_pagado,
            valor_glosa,
            glosa_recuperable,
            glosa_no_recuperable,
            fecha_ultimo_pago,
            periodo_inicio,
            periodo_fin,
            id_subgrupo_servicio,
            id_empresa_convenio,
            estado_factura,
            estado,
            id_forma_pago,
            observacion,
            usuario_crea,
            fecha
        ) VALUES (
            ?, ?, ?, ?, ?, ?, ?, ?, 
            0, 0, 0, 0, 0, 0, 0, NULL,?, ?, 
            ?, ?, 'prefactura', 2, 10, ?, ?, NOW()
        )
    ";

    $stmtLiquidacion = $conn->prepare($sqlLiquidacion);
    if (!$stmtLiquidacion) {
        throw new Exception('Error preparando liquidación: ' . $conn->error);
    }

    $totalPlan = $totalEPS;
    $observacionLiquidacion = $input['observacion'] ?? '';

    $stmtLiquidacion->bind_param(
        "idddddddssiiss",
        $idOrdenFactura,
        $totalOrden,
        $totalEPS,
        $totalPaciente,
        $totalPlan,
        $valorCopago,
        $valorModerada,
        $totalDescuento,
        $periodoInicio,
        $periodoFin,
        $idSubgrupoServicio,
        $input['empresa_eps_convenio'],
        $observacionLiquidacion,
        $usuario
    );

    if (!$stmtLiquidacion->execute()) {
        throw new Exception('Error al crear liquidación: ' . $stmtLiquidacion->error);
    }

    $idLiquidacion = $stmtLiquidacion->insert_id;
    error_log("✅ Liquidación creada: ID " . $idLiquidacion);
    $stmtLiquidacion->close();

    // ===================================================
    // 🚀 ¡AUTOMÁTICAMENTE CREAR LA FACTURA ELECTRÓNICA!
    // ===================================================
    try {
        $facturaInfo = crearFacturaElectronica($conn, $idLiquidacion, $usuario);
        error_log("✅ Factura electrónica creada automáticamente: " . ($facturaInfo['factura'] ?? 'N/A'));
    } catch (Exception $e) {
        // Si falla la creación de la factura, hacemos rollback de TODO
        throw new Exception("Error al crear factura electrónica automática: " . $e->getMessage());
    }

    // ===================================================
    // ✅ ACTUALIZAR ESTADO DE LA CITA
    // ===================================================
    $sqlUpdateCita = "UPDATE c_cita_programada SET estado_cita = 'Facturada' WHERE id = ?";
    $stmtUpdate = $conn->prepare($sqlUpdateCita);
    $stmtUpdate->bind_param("i", $idCita);
    $stmtUpdate->execute();
    $stmtUpdate->close();

    $conn->commit();
    error_log("✅ Transacción principal completada");

    // ===================================================
    // 🆕 CREAR ÓRDENES MÉDICAS FUERA DE LA TRANSACCIÓN
    // ===================================================
    // Esto evita que se pierdan si hay rollback
    $ordenesResult = crearOrdenesMedicasFueraTransaccion(
        $conn,
        $idCita,
        $input['id_datos_personales'],
        $idAtencion,
        $fecha_ingreso,
        $hora_ingreso,
        $input['procedimientos'],
        $id_finalidad,
        $id_grupo_servicio_rips,
        $id_servicio_rips,
        $usuario
    );

    if (!empty($ordenesResult['errores'])) {
        error_log("⚠️ Errores al crear órdenes médicas: " . implode(', ', $ordenesResult['errores']));
    }

    // Obtener el ID de la primera orden médica creada
    $idOrdenMedica = $ordenesResult['id_orden_medica'] ?? null;

    // Actualizar ordenes_fact con el id_orden_medica si se creó correctamente
    if ($idOrdenMedica) {
        $stmtUpdateOrden = $conn->prepare("UPDATE ordenes_fact SET id_orden_medica = ? WHERE id_orden_factura = ?");
        $stmtUpdateOrden->bind_param("ii", $idOrdenMedica, $idOrdenFactura);
        $stmtUpdateOrden->execute();
        $stmtUpdateOrden->close();
    }
    echo json_encode([
        'success' => true,
        'message' => 'Factura administrativa y electrónica creadas exitosamente',
        'data' => [
            'id_cita' => $idCita,
            'id_atencion' => $idAtencion,
            'id_orden_medica' => $idOrdenMedica,
            'id_orden_factura' => $idOrdenFactura,
            'id_liquidacion' => $idLiquidacion,
            'factura_electronica' => $facturaInfo,
            'total' => $totalOrden,
            'total_eps' => $totalEPS,
            'total_paciente' => $totalPaciente,
            'copago' => $valorCopago,
            'subgrupo_servicio' => $idSubgrupoServicio,
            'ordenes_medicas_result' => $ordenesResult

        ]
    ]);
} catch (Exception $e) {
    if (isset($conn) && $conn->ping()) {
        $conn->rollback();
    }

    error_log("❌ Error: " . $e->getMessage());
    echo json_encode([
        'success' => false,
        'message' => $e->getMessage()
    ]);
}
function normalizarHora($hora, $default = '00:00:00')
{
    if ($hora === null) return $default;

    $hora = trim((string)$hora);
    if ($hora === '') return $default;

    // Quitar AM/PM y convertir si viene en 12 horas
    $hora = strtoupper($hora);

    // Ej: 2:30 PM, 02:30 PM, 2:30PM
    if (preg_match('/^(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)$/i', $hora, $m)) {
        $h = (int)$m[1];
        $i = (int)$m[2];
        $s = isset($m[3]) && $m[3] !== '' ? (int)$m[3] : 0;
        $ampm = strtoupper($m[4]);

        if ($ampm === 'PM' && $h < 12) $h += 12;
        if ($ampm === 'AM' && $h == 12) $h = 0;

        return sprintf('%02d:%02d:%02d', $h, $i, $s);
    }

    // Ej: 14:30
    if (preg_match('/^(\d{1,2}):(\d{2})$/', $hora, $m)) {
        $h = (int)$m[1];
        $i = (int)$m[2];

        if ($h >= 0 && $h <= 23 && $i >= 0 && $i <= 59) {
            return sprintf('%02d:%02d:00', $h, $i);
        }
    }

    // Ej: 14:30:25
    if (preg_match('/^(\d{1,2}):(\d{2}):(\d{2})$/', $hora, $m)) {
        $h = (int)$m[1];
        $i = (int)$m[2];
        $s = (int)$m[3];

        if ($h >= 0 && $h <= 23 && $i >= 0 && $i <= 59 && $s >= 0 && $s <= 59) {
            return sprintf('%02d:%02d:%02d', $h, $i, $s);
        }
    }

    return $default;
}

function normalizarHoraInput($hora, $default = '00:00')
{
    $horaNormalizada = normalizarHora($hora, $default . ':00');
    return substr($horaNormalizada, 0, 5);
}
/**
 * Distribuye N fechas entre un inicio y un fin, incluyendo ambos extremos.
 * Si el rango es de un solo día, repite la misma fecha.
 */
function distribuirFechasEnPeriodo(string $periodoInicio, string $periodoFin, int $cantidad): array
{
    if ($cantidad <= 0) {
        return [];
    }

    $inicio = new DateTime($periodoInicio);
    $fin = new DateTime($periodoFin);

    if ($inicio > $fin) {
        throw new Exception('La fecha inicial no puede ser mayor que la fecha final.');
    }

    if ($cantidad === 1) {
        return [$inicio->format('Y-m-d')];
    }

    $diasTotales = (int)$inicio->diff($fin)->days;

    if ($diasTotales === 0) {
        return array_fill(0, $cantidad, $inicio->format('Y-m-d'));
    }

    $fechas = [];

    for ($i = 0; $i < $cantidad; $i++) {
        $offset = (int) round(($diasTotales * $i) / ($cantidad - 1));
        $fecha = clone $inicio;
        $fecha->modify("+{$offset} days");
        $fechas[] = $fecha->format('Y-m-d');
    }

    return $fechas;
}

/**
 * Distribuye un valor total en N partes sin perder centavos.
 * Devuelve strings con 2 decimales para evitar descuadres.
 */
function distribuirValoresUnitarios(float $valorTotal, int $cantidad): array
{
    if ($cantidad <= 0) {
        return [];
    }

    $totalCentavos = (int) round($valorTotal * 100);
    $baseCentavos = intdiv($totalCentavos, $cantidad);
    $residuo = $totalCentavos % $cantidad;

    $valores = [];

    for ($i = 0; $i < $cantidad; $i++) {
        $centavos = $baseCentavos;
        if ($i < $residuo) {
            $centavos++;
        }
        $valores[] = number_format($centavos / 100, 2, '.', '');
    }

    return $valores;
}
