<?php
/**
 * API: Cerrar Sesión de Caja
 * Sistema Sufarma
 */

header('Content-Type: application/json');
require_once '../../db_connection.php';

try {
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (!isset($input['sesion_id']) || empty($input['sesion_id'])) {
        throw new Exception("El ID de la sesión es requerido.");
    }
    if (!isset($input['monto_cierre_real']) || $input['monto_cierre_real'] === '') {
        throw new Exception("El monto de cierre real (efectivo físico) es requerido.");
    }
    if (!isset($input['usuario_id_cierre']) || empty($input['usuario_id_cierre'])) {
        throw new Exception("El cajero que realiza el cierre es requerido.");
    }
    
    $sesion_id = (int)$input['sesion_id'];
    $monto_cierre_real = floatval($input['monto_cierre_real']);
    $usuario_id_cierre = (int)$input['usuario_id_cierre'];
    $tipo_cierre = isset($input['tipo_cierre']) ? trim($input['tipo_cierre']) : 'final';
    
    if (!in_array($tipo_cierre, ['parcial', 'final'])) {
        throw new Exception("El tipo de cierre especificado es inválido.");
    }
    
    if ($monto_cierre_real < 0) {
        throw new Exception("El monto de cierre real no puede ser negativo.");
    }
    
    // Iniciar transacción para evitar inconsistencias
    $pdo->beginTransaction();
    
    // Obtener sesión de caja
    $sqlSesion = "SELECT cs.*, u.nombre as nombre_usuario 
                  FROM caja_sesiones cs
                  JOIN usuarios u ON cs.usuario_id = u.id
                  WHERE cs.id = :sesion_id AND cs.estado = 'abierta'
                  FOR UPDATE";
    $stmtSesion = $pdo->prepare($sqlSesion);
    $stmtSesion->execute(['sesion_id' => $sesion_id]);
    $sesion = $stmtSesion->fetch();
    
    if (!$sesion) {
        throw new Exception("La sesión de caja especificada no existe o ya se encuentra cerrada.");
    }
    
    // Calcular totales
    // Ventas en efectivo
    $ventasEfectivoStmt = $pdo->prepare("SELECT SUM(COALESCE(monto_efectivo, 0)) as total_efectivo FROM ventas WHERE caja_sesion_id = :sesion_id");
    $ventasEfectivoStmt->execute(['sesion_id' => $sesion_id]);
    $ve = $ventasEfectivoStmt->fetch();
    $ventas_efectivo = $ve ? floatval($ve['total_efectivo']) : 0;
    
    // Ventas con tarjeta (informativo)
    $ventasTarjetaStmt = $pdo->prepare("SELECT SUM(COALESCE(monto_tarjeta, 0)) as total_tarjeta FROM ventas WHERE caja_sesion_id = :sesion_id");
    $ventasTarjetaStmt->execute(['sesion_id' => $sesion_id]);
    $vt = $ventasTarjetaStmt->fetch();
    $ventas_tarjeta = $vt ? floatval($vt['total_tarjeta']) : 0;
    
    // Ventas totales (informativo)
    $ventasTotalStmt = $pdo->prepare("SELECT SUM(total) as total_ventas FROM ventas WHERE caja_sesion_id = :sesion_id");
    $ventasTotalStmt->execute(['sesion_id' => $sesion_id]);
    $vtot = $ventasTotalStmt->fetch();
    $ventas_total = $vtot ? floatval($vtot['total_ventas']) : 0;
    
    // Ingresos extras
    $ingresosStmt = $pdo->prepare("SELECT SUM(monto) as total_ingresos FROM caja_movimientos WHERE sesion_id = :sesion_id AND tipo = 'ingreso'");
    $ingresosStmt->execute(['sesion_id' => $sesion_id]);
    $ing = $ingresosStmt->fetch();
    $ingresos_extras = $ing ? floatval($ing['total_ingresos']) : 0;
    
    // Egresos
    $egresosStmt = $pdo->prepare("SELECT SUM(monto) as total_egresos FROM caja_movimientos WHERE sesion_id = :sesion_id AND tipo = 'egreso'");
    $egresosStmt->execute(['sesion_id' => $sesion_id]);
    $egr = $egresosStmt->fetch();
    $egresos = $egr ? floatval($egr['total_egresos']) : 0;
    
    $monto_apertura = floatval($sesion['monto_apertura']);
    $monto_cierre_teorico = $monto_apertura + $ventas_efectivo + $ingresos_extras - $egresos;
    $diferencia = $monto_cierre_real - $monto_cierre_teorico;
    
    // Si es corte parcial, guardar registro histórico en caja_cortes_parciales
    if ($tipo_cierre === 'parcial') {
        $insertParcial = $pdo->prepare("INSERT INTO caja_cortes_parciales 
            (sesion_id, usuario_id_cierre, monto_declarado, monto_esperado, diferencia, fecha_corte) 
            VALUES (:sesion_id, :usuario_id_cierre, :monto_declarado, :monto_esperado, :diferencia, CURRENT_TIMESTAMP)");
        $insertParcial->execute([
            'sesion_id' => $sesion_id,
            'usuario_id_cierre' => $usuario_id_cierre,
            'monto_declarado' => $monto_cierre_real,
            'monto_esperado' => $monto_cierre_teorico,
            'diferencia' => $diferencia
        ]);
    }
    
    // Actualizar sesión solo si es un cierre final
    if ($tipo_cierre === 'final') {
        $updateSql = "UPDATE caja_sesiones SET 
                        fecha_cierre = CURRENT_TIMESTAMP,
                        monto_cierre_teorico = :monto_cierre_teorico,
                        monto_cierre_real = :monto_cierre_real,
                        diferencia = :diferencia,
                        usuario_id_cierre = :usuario_id_cierre,
                        estado = 'cerrada'
                      WHERE id = :sesion_id";
                      
        $updateStmt = $pdo->prepare($updateSql);
        $updateStmt->execute([
            'monto_cierre_teorico' => $monto_cierre_teorico,
            'monto_cierre_real' => $monto_cierre_real,
            'diferencia' => $diferencia,
            'usuario_id_cierre' => $usuario_id_cierre,
            'sesion_id' => $sesion_id
        ]);
    }
    
    // Obtener datos del usuario de cierre
    $stmtCierreUser = $pdo->prepare("SELECT nombre FROM usuarios WHERE id = ?");
    $stmtCierreUser->execute([$usuario_id_cierre]);
    $cierreUserRow = $stmtCierreUser->fetch();
    $cajero_cierre_nombre = $cierreUserRow ? $cierreUserRow['nombre'] : 'Cajero de Cierre';
    
    // Consultar historial de cortes parciales de esta sesión (para incluir en el ticket final)
    $cortesParciales = [];
    if ($tipo_cierre === 'final') {
        $stmtParciales = $pdo->prepare(
            "SELECT cp.*, u.nombre as cajero_nombre 
             FROM caja_cortes_parciales cp 
             JOIN usuarios u ON cp.usuario_id_cierre = u.id 
             WHERE cp.sesion_id = :sesion_id 
             ORDER BY cp.fecha_corte ASC"
        );
        $stmtParciales->execute(['sesion_id' => $sesion_id]);
        $cortesParciales = $stmtParciales->fetchAll();
    }
    
    $pdo->commit();
    
    // Retornar los detalles finales para la impresión del ticket
    $resumen = [
        'id' => $sesion_id,
        'cajero' => $sesion['nombre_usuario'],
        'cajero_cierre' => $cajero_cierre_nombre,
        'fecha_apertura' => $sesion['fecha_apertura'],
        'fecha_cierre' => date('Y-m-d H:i:s'),
        'monto_apertura' => $monto_apertura,
        'ventas_efectivo' => $ventas_efectivo,
        'ventas_tarjeta' => $ventas_tarjeta,
        'ventas_total' => $ventas_total,
        'ingresos_extras' => $ingresos_extras,
        'egresos' => $egresos,
        'saldo_esperado' => $monto_cierre_teorico,
        'monto_cierre_real' => $monto_cierre_real,
        'diferencia' => $diferencia,
        'tipo_cierre' => $tipo_cierre
    ];
    
    // Incluir historial de cortes parciales solo en cierre final
    if ($tipo_cierre === 'final' && !empty($cortesParciales)) {
        $resumen['cortes_parciales'] = array_map(function($cp) {
            return [
                'hora' => $cp['fecha_corte'],
                'cajero' => $cp['cajero_nombre'],
                'declarado' => floatval($cp['monto_declarado']),
                'esperado' => floatval($cp['monto_esperado']),
                'diferencia' => floatval($cp['diferencia'])
            ];
        }, $cortesParciales);
    }
    
    echo json_encode([
        'success' => true,
        'message' => $tipo_cierre === 'parcial' ? 'Corte parcial generado exitosamente.' : 'Caja cerrada exitosamente.',
        'resumen' => $resumen
    ]);
} catch (Exception $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }
    http_response_code(400);
    echo json_encode([
        'success' => false,
        'error' => $e->getMessage()
    ]);
}
?>
