<?php
// Configurar zona horaria de Colombia (UTC-5)
date_default_timezone_set('America/Bogota');

session_start();
require_once 'auth.php';
require_once 'init_auth.php';
require_once 'init_ubicaciones.php';
require_once 'init_auditoria.php';

// Desactivar output de errores para evitar corrupción del JSON
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);

// Iniciar buffer de salida para capturar cualquier output inesperado
ob_start();

// Verificar autenticación para todas las operaciones
requireAuth();

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, DELETE, PUT, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    ob_clean();
    http_response_code(200);
    echo json_encode(['status' => 'ok']);
    exit;
}

$db_path = __DIR__ . '/inventario.db';

function init_db($db_path) {
    try {
        $db = getDbConnection($db_path);
        
        // Verificar si la tabla existe
        $tableExists = $db->querySingle("SELECT name FROM sqlite_master WHERE type='table' AND name='inventario'");
        
        if ($tableExists) {
            // Verificar qué columnas tiene la tabla
            $columns = $db->query("PRAGMA table_info(inventario)");
            $hasMetros = false;
            $hasKilos = false;
            
            if ($columns) {
                while ($col = $columns->fetchArray(SQLITE3_ASSOC)) {
                    if (isset($col['name'])) {
                        if ($col['name'] === 'metros') {
                            $hasMetros = true;
                        }
                        if ($col['name'] === 'kilos') {
                            $hasKilos = true;
                        }
                    }
                }
            }
            
            // Si tiene metros pero no kilos, necesitamos migrar
            if ($hasMetros && !$hasKilos) {
                // Migración: crear tabla temporal, copiar datos, reemplazar
                $db->exec('BEGIN TRANSACTION');
                
                try {
                    // Obtener admin ID para asignar registros antiguos
                    $stmt = $db->prepare('SELECT id FROM usuarios WHERE username = ?');
                    $stmt->bindValue(1, 'admin', SQLITE3_TEXT);
                    $result = $stmt->execute();
                    $admin = $result->fetchArray(SQLITE3_ASSOC);
                    $defaultUserId = $admin ? $admin['id'] : 1;
                    
                    // Crear tabla nueva con todas las columnas necesarias
                    // Obtener la toma del usuario admin
                    $stmt_toma = $db->prepare('SELECT toma FROM usuarios WHERE id = ?');
                    $stmt_toma->bindValue(1, $defaultUserId, SQLITE3_INTEGER);
                    $result_toma = $stmt_toma->execute();
                    $user_toma = $result_toma->fetchArray(SQLITE3_ASSOC);
                    $defaultToma = $user_toma['toma'] ?? NULL;
                    
                    $db->exec('CREATE TABLE inventario_new (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        codigo_tela TEXT NOT NULL,
                        kilos REAL NOT NULL,
                        fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                        numero_completo TEXT NOT NULL,
                        ubicacion_id INTEGER,
                        usuario_id INTEGER NOT NULL,
                        toma TEXT,
                        UNIQUE(numero_completo, toma)
                    )');
                    
                    // Copiar datos (metros -> kilos) y asignar al admin
                    $db->exec("INSERT INTO inventario_new (id, codigo_tela, kilos, fecha_registro, numero_completo, ubicacion_id, usuario_id, toma)
                               SELECT id, codigo_tela, metros AS kilos, fecha_registro, numero_completo, 
                                      COALESCE(ubicacion_id, NULL), {$defaultUserId}, '{$defaultToma}' FROM inventario");
                    
                    // Eliminar tabla vieja
                    $db->exec('DROP TABLE inventario');
                    
                    // Renombrar tabla nueva
                    $db->exec('ALTER TABLE inventario_new RENAME TO inventario');
                    
                    $db->exec('COMMIT');
                } catch (Exception $e) {
                    $db->exec('ROLLBACK');
                    throw $e;
                }
            }
            // Si no tiene kilos ni metros, algo está mal - recrear tabla
            else if (!$hasKilos && !$hasMetros) {
                $db->exec('DROP TABLE inventario');
                $db->exec('CREATE TABLE inventario (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    codigo_tela TEXT NOT NULL,
                    kilos REAL NOT NULL,
                    fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    numero_completo TEXT NOT NULL,
                    ubicacion_id INTEGER,
                    usuario_id INTEGER NOT NULL,
                    toma TEXT,
                    UNIQUE(numero_completo, toma)
                )');
            }
            // Si tiene kilos, verificar si tiene usuario_id
            else {
                $columns = $db->query("PRAGMA table_info(inventario)");
                $hasUsuarioId = false;
                if ($columns) {
                    while ($col = $columns->fetchArray(SQLITE3_ASSOC)) {
                        if (isset($col['name']) && $col['name'] === 'usuario_id') {
                            $hasUsuarioId = true;
                            break;
                        }
                    }
                }
                
                // Verificar si tiene campo toma
                $hasToma = false;
                $columns = $db->query("PRAGMA table_info(inventario)");
                if ($columns) {
                    while ($col = $columns->fetchArray(SQLITE3_ASSOC)) {
                        if (isset($col['name']) && $col['name'] === 'toma') {
                            $hasToma = true;
                            break;
                        }
                    }
                }
                
                if (!$hasToma || !$hasUsuarioId) {
                    // Agregar columnas si no existen
                    if (!$hasUsuarioId) {
                        $db->exec('ALTER TABLE inventario ADD COLUMN usuario_id INTEGER');
                    }
                    if (!$hasToma) {
                        $db->exec('ALTER TABLE inventario ADD COLUMN toma TEXT');
                    }
                    
                    // Obtener admin para asignar datos antiguos
                    $stmt = $db->prepare('SELECT id, toma FROM usuarios WHERE username = ?');
                    $stmt->bindValue(1, 'admin', SQLITE3_TEXT);
                    $result = $stmt->execute();
                    $admin = $result->fetchArray(SQLITE3_ASSOC);
                    $defaultUserId = $admin ? $admin['id'] : 1;
                    $defaultToma = $admin && !empty($admin['toma']) ? $admin['toma'] : NULL;
                    
                    // Actualizar registros sin usuario_id o toma
                    $db->exec("UPDATE inventario SET usuario_id = {$defaultUserId} WHERE usuario_id IS NULL");
                    if ($defaultToma) {
                        $db->exec("UPDATE inventario SET toma = '{$defaultToma}' WHERE toma IS NULL");
                    }
                    
                    // Recrear tabla con restricción UNIQUE(numero_completo, toma)
                    try {
                        $db->exec('BEGIN TRANSACTION');
                        
                        $db->exec('CREATE TABLE inventario_temp (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            codigo_tela TEXT NOT NULL,
                            kilos REAL NOT NULL,
                            numero_completo TEXT NOT NULL,
                            fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                            ubicacion_id INTEGER,
                            usuario_id INTEGER NOT NULL,
                            toma TEXT,
                            UNIQUE(numero_completo, toma)
                        )');
                        
                        if ($defaultToma) {
                            $db->exec("INSERT INTO inventario_temp (id, codigo_tela, kilos, numero_completo, fecha_registro, ubicacion_id, usuario_id, toma)
                                       SELECT id, codigo_tela, kilos, numero_completo, fecha_registro, ubicacion_id, 
                                              COALESCE(usuario_id, {$defaultUserId}), 
                                              COALESCE(toma, '{$defaultToma}')
                                       FROM inventario");
                        } else {
                            $db->exec("INSERT INTO inventario_temp (id, codigo_tela, kilos, numero_completo, fecha_registro, ubicacion_id, usuario_id, toma)
                                       SELECT id, codigo_tela, kilos, numero_completo, fecha_registro, ubicacion_id, 
                                              COALESCE(usuario_id, {$defaultUserId}), 
                                              toma
                                       FROM inventario");
                        }
                        
                        $db->exec('DROP TABLE inventario');
                        $db->exec('ALTER TABLE inventario_temp RENAME TO inventario');
                        
                        $db->exec('COMMIT');
                    } catch (Exception $e) {
                        $db->exec('ROLLBACK');
                        error_log('Error en migración toma/usuario_id: ' . $e->getMessage());
                    }
                }
            }
        } else {
            // Crear tabla nueva
            $db->exec('CREATE TABLE inventario (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                codigo_tela TEXT NOT NULL,
                kilos REAL NOT NULL,
                fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                numero_completo TEXT NOT NULL,
                ubicacion_id INTEGER,
                usuario_id INTEGER NOT NULL,
                toma TEXT,
                UNIQUE(numero_completo, toma)
            )');
        }
        
        // Verificar y agregar columnas relacionadas con CSV y nota si no existen
        $columns = $db->query("PRAGMA table_info(inventario)");
        $hasCodigoExisteCSV = false;
        $hasNombreItem = false;
        $hasColor = false;
        $hasNota = false;
        if ($columns) {
            while ($col = $columns->fetchArray(SQLITE3_ASSOC)) {
                if (isset($col['name'])) {
                    if ($col['name'] === 'codigo_existe_csv') {
                        $hasCodigoExisteCSV = true;
                    }
                    if ($col['name'] === 'nombre_item') {
                        $hasNombreItem = true;
                    }
                    if ($col['name'] === 'color') {
                        $hasColor = true;
                    }
                    if ($col['name'] === 'nota') {
                        $hasNota = true;
                    }
                }
            }
        }
        if (!$hasCodigoExisteCSV) {
            $db->exec('ALTER TABLE inventario ADD COLUMN codigo_existe_csv INTEGER DEFAULT 0');
        }
        if (!$hasNombreItem) {
            $db->exec('ALTER TABLE inventario ADD COLUMN nombre_item TEXT');
        }
        if (!$hasColor) {
            $db->exec('ALTER TABLE inventario ADD COLUMN color TEXT');
        }
        if (!$hasNota) {
            $db->exec('ALTER TABLE inventario ADD COLUMN nota TEXT');
        }
        
        $db->close();
        return true;
    } catch (Exception $e) {
        error_log('Error inicializando base de datos: ' . $e->getMessage());
        return false;
    }
}

function parse_qr_code($numero_completo) {
    // Convertir a string y limpiar
    $numero_completo = (string)$numero_completo;
    
    // Eliminar caracteres de control comunes de lectores de códigos de barras
    // Esto incluye: espacios, saltos de línea, retornos de carro, tabs, etc.
    $numero_completo = preg_replace('/[\x00-\x1F\x7F-\x9F]/', '', $numero_completo);
    $numero_completo = trim($numero_completo);
    
    // Normalizar separador decimal: convertir coma a punto
    $numero_completo = str_replace(',', '.', $numero_completo);
    
    // Remover espacios
    $numero_completo = str_replace(' ', '', $numero_completo);
    
    // Validar que tenga al menos 8 caracteres (7 para código + 1 para kilos mínimo)
    if (strlen($numero_completo) < 8) {
        return [null, null, 'El código debe tener al menos 8 caracteres (7 para código + kilos). Recibido: ' . substr($numero_completo, 0, 20)];
    }
    
    // Los primeros 7 caracteres son el código completo
    $codigo_tela = substr($numero_completo, 0, 7);
    
    // Validar que el código tenga solo números
    if (!preg_match('/^[0-9]+$/', $codigo_tela)) {
        return [null, null, 'El código debe contener solo números en los primeros 7 caracteres. Recibido: ' . substr($numero_completo, 0, 20)];
    }
    
    // Los caracteres siguientes (desde el 8vo) son los kilos
    $kilos_str = substr($numero_completo, 7);
    
    // Limpiar kilos: permitir números, punto o coma decimal
    $kilos_str = preg_replace('/[^0-9.]/', '', $kilos_str);
    
    // Validar que los kilos sean un número válido
    if (empty($kilos_str) || !is_numeric($kilos_str)) {
        return [null, null, 'Los kilos deben ser un número válido. Recibido: ' . substr($numero_completo, 7, 10)];
    }
    
    $kilos = (float)$kilos_str;
    
    // Validar que los kilos sean válidos (no negativos)
    if ($kilos < 0) {
        return [null, null, 'Los kilos no pueden ser negativos. Obtenido: ' . $kilos_str];
    }
    
    return [$codigo_tela, $kilos, null];
}

// Función para verificar si un código existe en inventario.csv y obtener información adicional
function verificarCodigoEnCSV($codigo) {
    try {
        $csv_path = __DIR__ . '/inventario.csv';
        
        if (!file_exists($csv_path)) {
            return ['existe' => false, 'nombre_item' => null, 'color' => null];
        }
        
        $handle = @fopen($csv_path, 'r');
        if ($handle === false) {
            return ['existe' => false, 'nombre_item' => null, 'color' => null];
        }
        
        $codigo_limpio = trim($codigo);
        $linea_num = 0;
        
        while (($row = @fgetcsv($handle, 2000, ',')) !== false) {
            $linea_num++;
            
            // Saltar primera línea (encabezado) y segunda línea (Gran total)
            if ($linea_num <= 2) {
                continue;
            }
            
            // Obtener código de la primera columna
            if (isset($row[0])) {
                $codigo_csv = trim($row[0], ' "');
                $codigo_csv_limpio = trim($codigo_csv);
                
                // Comparar códigos directamente, o buscar el código numérico dentro del código del CSV
                if ($codigo_csv_limpio === $codigo_limpio || strpos($codigo_csv_limpio, $codigo_limpio) !== false) {
                    // Obtener nombre del item (columna 2, índice 1)
                    $nombre_item = isset($row[1]) ? trim($row[1], ' "') : null;
                    // Obtener color (columna 7, índice 6)
                    $color = isset($row[6]) ? trim($row[6], ' "') : null;
                    
                    // Convertir a UTF-8 válido para evitar errores en json_encode
                    if ($nombre_item !== null && !mb_check_encoding($nombre_item, 'UTF-8')) {
                        $nombre_item = mb_convert_encoding($nombre_item, 'UTF-8', 'ISO-8859-1');
                    }
                    if ($color !== null && !mb_check_encoding($color, 'UTF-8')) {
                        $color = mb_convert_encoding($color, 'UTF-8', 'ISO-8859-1');
                    }
                    
                    @fclose($handle);
                    return [
                        'existe' => true,
                        'nombre_item' => $nombre_item ?: null,
                        'color' => $color ?: null
                    ];
                }
            }
        }
        
        @fclose($handle);
        return ['existe' => false, 'nombre_item' => null, 'color' => null];
    } catch (Exception $e) {
        error_log('Error en verificarCodigoEnCSV: ' . $e->getMessage());
        if (isset($handle) && is_resource($handle)) {
            @fclose($handle);
        }
        return ['existe' => false, 'nombre_item' => null, 'color' => null];
    } catch (Error $e) {
        error_log('Error fatal en verificarCodigoEnCSV: ' . $e->getMessage());
        if (isset($handle) && is_resource($handle)) {
            @fclose($handle);
        }
        return ['existe' => false, 'nombre_item' => null, 'color' => null];
    }
}

// Limpiar cualquier output previo (si el buffer existe)
if (ob_get_level() > 0) {
    ob_clean();
}

// Verificar si SQLite3 está disponible
if (!class_exists('SQLite3')) {
    ob_clean();
    http_response_code(500);
    echo json_encode(['error' => 'SQLite3 no está disponible en este servidor']);
    exit;
}

if (!init_db($db_path)) {
    ob_clean();
    http_response_code(500);
    echo json_encode(['error' => 'Error al inicializar la base de datos. Verifique permisos de escritura.']);
    exit;
}

// Inicializar tabla de auditoría
try {
    init_auditoria($db_path);
} catch (Exception $e) {
    error_log('Error inicializando auditoría: ' . $e->getMessage());
    // Continuar sin auditoría si hay error
} catch (Error $e) {
    error_log('Error fatal inicializando auditoría: ' . $e->getMessage());
    // Continuar sin auditoría si hay error
}

// Función para registrar eventos de auditoría
function registrarAuditoria($db, $accion, $tipo_registro, $registro_id, $datos = []) {
    try {
        $usuario_id = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
        $usuario_username = isset($_SESSION['username']) ? $_SESSION['username'] : 'Desconocido';
        
        if (!$usuario_id) {
            return false;
        }
        
        $stmt = $db->prepare('INSERT INTO auditoria (
            usuario_id, usuario_username, accion, tipo_registro, registro_id, 
            codigo_tela, kilos, toma, ubicacion_anterior_id, ubicacion_anterior_codigo,
            ubicacion_nueva_id, ubicacion_nueva_codigo, detalles, fecha_accion
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
        
        $stmt->bindValue(1, $usuario_id, SQLITE3_INTEGER);
        $stmt->bindValue(2, $usuario_username, SQLITE3_TEXT);
        $stmt->bindValue(3, $accion, SQLITE3_TEXT);
        $stmt->bindValue(4, $tipo_registro, SQLITE3_TEXT);
        $stmt->bindValue(5, $registro_id, SQLITE3_INTEGER);
        $stmt->bindValue(6, $datos['codigo_tela'] ?? null, SQLITE3_TEXT);
        $stmt->bindValue(7, $datos['kilos'] ?? null, SQLITE3_FLOAT);
        $stmt->bindValue(8, $datos['toma'] ?? null, SQLITE3_TEXT);
        $stmt->bindValue(9, $datos['ubicacion_anterior_id'] ?? null, SQLITE3_INTEGER);
        $stmt->bindValue(10, $datos['ubicacion_anterior_codigo'] ?? null, SQLITE3_TEXT);
        $stmt->bindValue(11, $datos['ubicacion_nueva_id'] ?? null, SQLITE3_INTEGER);
        $stmt->bindValue(12, $datos['ubicacion_nueva_codigo'] ?? null, SQLITE3_TEXT);
        $stmt->bindValue(13, $datos['detalles'] ?? null, SQLITE3_TEXT);
        $stmt->bindValue(14, date('Y-m-d H:i:s'), SQLITE3_TEXT);
        
        $stmt->execute();
        return true;
    } catch (Exception $e) {
        error_log('Error al registrar auditoría: ' . $e->getMessage());
        return false;
    }
}

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$id_param = isset($_GET['id']) ? (int)$_GET['id'] : null;

if ($method === 'POST') {
    try {
        $raw_input = file_get_contents('php://input');
        if ($raw_input === false) {
            throw new Exception('No se pudo leer el input');
        }
        
        $data = json_decode($raw_input, true);
        
        // Si JSON decode falla, intentar procesar como texto plano
        if (json_last_error() !== JSON_ERROR_NONE) {
            $numero_completo = trim($raw_input);
            // Remover comillas si las hay
            $numero_completo = trim($numero_completo, '"\'');
        } else {
            $numero_completo = isset($data['numero_completo']) ? (string)$data['numero_completo'] : '';
        }
        
        $nota = isset($data['nota']) ? trim($data['nota']) : null;
        if ($nota === '') {
            $nota = null;
        }
        
        if (empty($numero_completo)) {
            ob_clean();
            http_response_code(400);
            echo json_encode(['error' => 'Número requerido']);
            exit;
        }
        
        list($codigo_tela, $kilos, $error_msg) = parse_qr_code($numero_completo);
        
        if ($codigo_tela === null || $kilos === null) {
            ob_clean();
            http_response_code(400);
            $response = ['error' => $error_msg ?: 'Formato de número inválido'];
            echo json_encode($response, JSON_UNESCAPED_UNICODE);
            exit;
        }
        
        // Obtener el número completo original (limpio) que se recibió
        // Limpiar solo caracteres de control, pero mantener punto/coma decimal
        $numero_limpio_guardar = preg_replace('/[\x00-\x1F\x7F-\x9F]/', '', trim($numero_completo));
        $numero_limpio_guardar = trim($numero_limpio_guardar);
        // Normalizar coma a punto para consistencia
        $numero_limpio_guardar = str_replace(',', '.', $numero_limpio_guardar);
        
        $db = getDbConnection($db_path);
        
        // Obtener usuario_id de la sesión
        $usuario_id = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
        
        if ($usuario_id === null) {
            ob_clean();
            http_response_code(401);
            echo json_encode(['error' => 'Usuario no autenticado']);
            exit;
        }
        
        // Verificar que el usuario no sea administrador
        if (isAdmin()) {
            $db->close();
            ob_clean();
            http_response_code(403);
            echo json_encode(['error' => 'Los administradores no pueden registrar inventario. Solo usuarios con toma asignada (toma1 o toma2) pueden registrar inventario.']);
            exit;
        }
        
        // Obtener la "toma" del usuario
        $stmt_user = $db->prepare('SELECT toma FROM usuarios WHERE id = ?');
        $stmt_user->bindValue(1, $usuario_id, SQLITE3_INTEGER);
        $result_user = $stmt_user->execute();
        $user_data = $result_user->fetchArray(SQLITE3_ASSOC);
        
        if (!$user_data || empty($user_data['toma'])) {
            $db->close();
            ob_clean();
            http_response_code(400);
            echo json_encode(['error' => 'El usuario debe tener asignada una toma (toma1 o toma2) para poder registrar inventario']);
            exit;
        }
        
        $toma = $user_data['toma'];
        
        // Verificar si el código ya existe PARA ESTA TOMA
        $stmt_check = $db->prepare('SELECT id, codigo_tela, kilos, fecha_registro FROM inventario WHERE numero_completo = ? AND toma = ?');
        if (!$stmt_check) {
            $db->close();
            throw new Exception('Error al preparar la consulta de verificación');
        }
        
        $stmt_check->bindValue(1, $numero_limpio_guardar, SQLITE3_TEXT);
        $stmt_check->bindValue(2, $toma, SQLITE3_TEXT);
        $result_check = $stmt_check->execute();
        
        if ($result_check) {
            $existing = $result_check->fetchArray(SQLITE3_ASSOC);
            if ($existing) {
                $db->close();
                ob_clean();
                http_response_code(409); // Conflict
                $fecha_existente = date('d/m/Y H:i', strtotime($existing['fecha_registro']));
                $response = [
                    'error' => 'Este código ya fue escaneado anteriormente en ' . $toma,
                    'duplicado' => true,
                    'fecha_registro' => $existing['fecha_registro'],
                    'fecha_formateada' => $fecha_existente,
                    'codigo_tela' => $existing['codigo_tela'],
                    'kilos' => $existing['kilos']
                ];
                echo json_encode($response, JSON_UNESCAPED_UNICODE);
                exit;
            }
        }
        
        // Obtener ubicación_id de la sesión
        $ubicacion_id = isset($_SESSION['ubicacion_actual_id']) ? (int)$_SESSION['ubicacion_actual_id'] : null;
        
        // Obtener fecha actual en zona horaria de Colombia
        $fecha_actual = date('Y-m-d H:i:s');
        
        if ($ubicacion_id === null) {
            ob_clean();
            http_response_code(400);
            echo json_encode(['error' => 'Debe seleccionar una ubicación antes de registrar inventario']);
            exit;
        }
        
        // Verificar si el código existe en inventario.csv ANTES de guardar
        $datos_csv = verificarCodigoEnCSV($codigo_tela);
        $codigo_existe_csv = $datos_csv['existe'] ? 1 : 0;
        $nombre_item = $datos_csv['nombre_item'] ?: null;
        $color = $datos_csv['color'] ?: null;
        
        $stmt = $db->prepare('INSERT INTO inventario (codigo_tela, kilos, numero_completo, fecha_registro, ubicacion_id, usuario_id, toma, codigo_existe_csv, nombre_item, color, nota) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
        if (!$stmt) {
            $error_msg_db = $db->lastErrorMsg();
            $db->close();
            throw new Exception('Error al preparar la consulta: ' . $error_msg_db);
        }
        
        $stmt->bindValue(1, $codigo_tela, SQLITE3_TEXT);
        $stmt->bindValue(2, $kilos, SQLITE3_FLOAT); // FLOAT para soportar decimales
        $stmt->bindValue(3, $numero_limpio_guardar, SQLITE3_TEXT);
        $stmt->bindValue(4, $fecha_actual, SQLITE3_TEXT);
        $stmt->bindValue(5, $ubicacion_id, SQLITE3_INTEGER);
        $stmt->bindValue(6, $usuario_id, SQLITE3_INTEGER);
        $stmt->bindValue(7, $toma, SQLITE3_TEXT);
        $stmt->bindValue(8, $codigo_existe_csv, SQLITE3_INTEGER);
        $stmt->bindValue(9, $nombre_item, SQLITE3_TEXT);
        $stmt->bindValue(10, $color, SQLITE3_TEXT);
        $stmt->bindValue(11, $nota, SQLITE3_TEXT);
        
        $result = $stmt->execute();
        if (!$result) {
            $error_msg_db = $db->lastErrorMsg();
            $db->close();
            
            // Verificar si es un error de restricción UNIQUE
            if (strpos($error_msg_db, 'UNIQUE constraint') !== false || strpos($error_msg_db, 'unique') !== false) {
                ob_clean();
                http_response_code(409); // Conflict
                $response = [
                    'error' => 'Este código ya existe en ' . $toma . '. No se pueden registrar códigos duplicados en la misma toma.',
                    'duplicado' => true
                ];
                echo json_encode($response, JSON_UNESCAPED_UNICODE);
                exit;
            }
            
            throw new Exception('Error al ejecutar la consulta: ' . $error_msg_db);
        }
        
        $id = $db->lastInsertRowID();
        $db->close();
        
        ob_clean();
        http_response_code(201);
        $response = [
            'id' => (int)$id,
            'codigo_tela' => $codigo_tela,
            'kilos' => (float)$kilos, // FLOAT para soportar decimales
            'numero_completo' => $numero_limpio_guardar,
            'ubicacion_id' => $ubicacion_id,
            'codigo_existe_csv' => (bool)$codigo_existe_csv,
            'nombre_item' => $nombre_item,
            'color' => $color,
            'nota' => $nota
        ];
        echo json_encode($response, JSON_UNESCAPED_UNICODE);
    } catch (Exception $e) {
        ob_clean();
        http_response_code(500);
        $error_response = ['error' => 'Error al procesar la solicitud: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')];
        echo json_encode($error_response, JSON_UNESCAPED_UNICODE);
        exit;
    } catch (Error $e) {
        ob_clean();
        http_response_code(500);
        $error_response = ['error' => 'Error fatal: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')];
        echo json_encode($error_response, JSON_UNESCAPED_UNICODE);
        exit;
    }
    exit;
}

if ($method === 'GET') {
    try {
        // Limpiar cualquier output previo
        if (ob_get_level() > 0) {
            ob_clean();
        }
        
        // Si se solicita información de un código sin registrar
        if (isset($_GET['info_codigo'])) {
            try {
                $numero_completo = $_GET['info_codigo'];
                
                // Parsear el código
                list($codigo_tela, $kilos, $error) = parse_qr_code($numero_completo);
                
                if ($error) {
                    ob_clean();
                    http_response_code(400);
                    echo json_encode(['error' => $error], JSON_UNESCAPED_UNICODE);
                    exit;
                }
                
                // Obtener información del CSV
                $datos_csv = verificarCodigoEnCSV($codigo_tela);
                
                ob_clean();
                echo json_encode([
                    'codigo_tela' => $codigo_tela,
                    'kilos' => $kilos,
                    'nombre_item' => $datos_csv['nombre_item'],
                    'color' => $datos_csv['color'],
                    'codigo_existe_csv' => $datos_csv['existe']
                ], JSON_UNESCAPED_UNICODE);
                exit;
            } catch (Exception $e) {
                ob_clean();
                http_response_code(500);
                echo json_encode(['error' => 'Error al procesar el código: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')], JSON_UNESCAPED_UNICODE);
                exit;
            } catch (Error $e) {
                ob_clean();
                http_response_code(500);
                echo json_encode(['error' => 'Error fatal: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')], JSON_UNESCAPED_UNICODE);
                exit;
            }
        }
        
        $db = getDbConnection($db_path);
        
        // Si es admin o lector, ver todos los registros, sino solo los de la toma del usuario
        $usuario_id = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
        $isAdmin = isAdmin();
        $isLector = isLector();
        
        if ($isAdmin || $isLector) {
            // Admin y lector ven todos los registros con información del usuario y toma
            $result = $db->query('SELECT i.id, i.codigo_tela, i.kilos, i.fecha_registro, i.numero_completo, 
                                         i.ubicacion_id, u.codigo as ubicacion_codigo, u.nombre as ubicacion_nombre,
                                         i.usuario_id, i.toma, us.username as usuario_username, us.nombre_completo as usuario_nombre,
                                         i.codigo_existe_csv, i.nombre_item, i.color, i.nota
                                  FROM inventario i
                                  LEFT JOIN ubicaciones u ON i.ubicacion_id = u.id
                                  LEFT JOIN usuarios us ON i.usuario_id = us.id
                                  ORDER BY i.fecha_registro DESC');
            
            if ($result === false) {
                $error_msg = $db->lastErrorMsg();
                $db->close();
                throw new Exception('Error en consulta: ' . $error_msg);
            }
        } else {
            // Usuario normal solo ve los registros que él creó
            if (!$usuario_id) {
                $db->close();
                if (ob_get_level() > 0) {
                    ob_clean();
                }
                echo json_encode([]);
                exit;
            }
            
            $stmt = $db->prepare('SELECT i.id, i.codigo_tela, i.kilos, i.fecha_registro, i.numero_completo, 
                                         i.ubicacion_id, u.codigo as ubicacion_codigo, u.nombre as ubicacion_nombre,
                                         i.usuario_id, i.toma, i.codigo_existe_csv, i.nombre_item, i.color, i.nota
                                  FROM inventario i
                                  LEFT JOIN ubicaciones u ON i.ubicacion_id = u.id
                                  WHERE i.usuario_id = ?
                                  ORDER BY i.fecha_registro DESC');
            $stmt->bindValue(1, $usuario_id, SQLITE3_INTEGER);
            $result = $stmt->execute();
            
            if ($result === false) {
                $error_msg = $db->lastErrorMsg();
                $db->close();
                throw new Exception('Error en consulta: ' . $error_msg);
            }
        }
        
        $inventario = [];
        if ($result) {
            while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
                $inventario[] = $row;
            }
        }
        $db->close();
        
        // Limpiar output antes de enviar JSON
        if (ob_get_level() > 0) {
            ob_clean();
        }
        echo json_encode($inventario, JSON_UNESCAPED_UNICODE);
    } catch (Exception $e) {
        if (ob_get_level() > 0) {
            ob_clean();
        }
        http_response_code(500);
        echo json_encode(['error' => 'Error al leer la base de datos: ' . $e->getMessage()]);
    } catch (Error $e) {
        if (ob_get_level() > 0) {
            ob_clean();
        }
        http_response_code(500);
        echo json_encode(['error' => 'Error fatal: ' . $e->getMessage()]);
    }
    exit;
}

if ($method === 'PUT' && $id_param !== null) {
    // Solo administradores pueden trasladar rollos
    requireAdmin();
    
    $item_id = $id_param;
    $raw_input = file_get_contents('php://input');
    $data = json_decode($raw_input, true);
    
    if (!isset($data['ubicacion_id'])) {
        ob_clean();
        http_response_code(400);
        echo json_encode(['error' => 'ubicacion_id es requerido']);
        exit;
    }
    
    $ubicacion_id = (int)$data['ubicacion_id'];
    
    try {
        ob_clean();
        $db = getDbConnection($db_path);
        
        // Obtener información del rollo antes de trasladar (para auditoría)
        $stmt_rollo = $db->prepare('SELECT i.id, i.codigo_tela, i.kilos, i.toma, i.ubicacion_id,
                                           u_old.codigo as ubicacion_anterior_codigo
                                    FROM inventario i
                                    LEFT JOIN ubicaciones u_old ON i.ubicacion_id = u_old.id
                                    WHERE i.id = ?');
        $stmt_rollo->bindValue(1, $item_id, SQLITE3_INTEGER);
        $result_rollo = $stmt_rollo->execute();
        $rollo_anterior = $result_rollo->fetchArray(SQLITE3_ASSOC);
        
        if (!$rollo_anterior) {
            $db->close();
            http_response_code(404);
            echo json_encode(['error' => 'Rollo no encontrado']);
            exit;
        }
        
        // Verificar que la ubicación nueva existe
        $stmt_check = $db->prepare('SELECT id, codigo FROM ubicaciones WHERE id = ? AND activa = 1');
        $stmt_check->bindValue(1, $ubicacion_id, SQLITE3_INTEGER);
        $result_check = $stmt_check->execute();
        $ubicacion_nueva = $result_check->fetchArray(SQLITE3_ASSOC);
        
        if (!$ubicacion_nueva) {
            $db->close();
            http_response_code(404);
            echo json_encode(['error' => 'Ubicación no encontrada']);
            exit;
        }
        
        // Actualizar la ubicación del rollo
        $stmt = $db->prepare('UPDATE inventario SET ubicacion_id = ? WHERE id = ?');
        if (!$stmt) {
            $db->close();
            throw new Exception('Error al preparar la consulta');
        }
        
        $stmt->bindValue(1, $ubicacion_id, SQLITE3_INTEGER);
        $stmt->bindValue(2, $item_id, SQLITE3_INTEGER);
        $result = $stmt->execute();
        
        if (!$result) {
            $db->close();
            throw new Exception('Error al ejecutar la consulta');
        }
        
        $updated = $db->changes() > 0;
        
        if ($updated) {
            // Registrar auditoría del traslado
            registrarAuditoria($db, 'TRASLADAR', 'inventario', $item_id, [
                'codigo_tela' => $rollo_anterior['codigo_tela'],
                'kilos' => $rollo_anterior['kilos'],
                'toma' => $rollo_anterior['toma'],
                'ubicacion_anterior_id' => $rollo_anterior['ubicacion_id'],
                'ubicacion_anterior_codigo' => $rollo_anterior['ubicacion_anterior_codigo'],
                'ubicacion_nueva_id' => $ubicacion_id,
                'ubicacion_nueva_codigo' => $ubicacion_nueva['codigo']
            ]);
            
            // Obtener la información actualizada del rollo
            $stmt_get = $db->prepare('SELECT i.id, i.codigo_tela, i.kilos, i.fecha_registro, i.numero_completo, 
                                             i.ubicacion_id, u.codigo as ubicacion_codigo, u.nombre as ubicacion_nombre
                                      FROM inventario i
                                      LEFT JOIN ubicaciones u ON i.ubicacion_id = u.id
                                      WHERE i.id = ?');
            $stmt_get->bindValue(1, $item_id, SQLITE3_INTEGER);
            $result_get = $stmt_get->execute();
            $rollo_actualizado = $result_get->fetchArray(SQLITE3_ASSOC);
            
            $db->close();
            echo json_encode(['success' => true, 'message' => 'Rollo trasladado exitosamente', 'rollo' => $rollo_actualizado]);
        } else {
            $db->close();
            http_response_code(404);
            echo json_encode(['error' => 'Rollo no encontrado']);
        }
    } catch (Exception $e) {
        ob_clean();
        http_response_code(500);
        echo json_encode(['error' => 'Error al trasladar el rollo: ' . $e->getMessage()]);
    }
    exit;
}

if ($method === 'DELETE' && $id_param !== null) {
    // Solo administradores pueden eliminar registros
    requireAdmin();
    
    $item_id = $id_param;
    
    try {
        ob_clean();
        $db = getDbConnection($db_path);

        // Obtener información del registro antes de eliminar para auditoría
        $stmt_get = $db->prepare('SELECT i.id, i.codigo_tela, i.kilos, i.toma, i.ubicacion_id, 
                                         u.codigo as ubicacion_codigo
                                  FROM inventario i
                                  LEFT JOIN ubicaciones u ON i.ubicacion_id = u.id
                                  WHERE i.id = ?');
        $stmt_get->bindValue(1, $item_id, SQLITE3_INTEGER);
        $result_get = $stmt_get->execute();
        $registro = $result_get->fetchArray(SQLITE3_ASSOC);
        
        if (!$registro) {
            $db->close();
            http_response_code(404);
            echo json_encode(['error' => 'Item no encontrado']);
            exit;
        }
        
        // Registrar auditoría antes de eliminar
        registrarAuditoria($db, 'ELIMINAR', 'inventario', $item_id, [
            'codigo_tela' => $registro['codigo_tela'],
            'kilos' => $registro['kilos'],
            'toma' => $registro['toma'],
            'ubicacion_anterior_id' => $registro['ubicacion_id'],
            'ubicacion_anterior_codigo' => $registro['ubicacion_codigo']
        ]);
        
        $stmt = $db->prepare('DELETE FROM inventario WHERE id = ?');
        if (!$stmt) {
            $db->close();
            throw new Exception('Error al preparar la consulta');
        }
        
        $stmt->bindValue(1, $item_id, SQLITE3_INTEGER);
        $result = $stmt->execute();
        
        if (!$result) {
            $db->close();
            throw new Exception('Error al ejecutar la consulta');
        }
        
        $deleted = $db->changes() > 0;
        $db->close();
        
        if ($deleted) {
            echo json_encode(['message' => 'Item eliminado']);
        } else {
            http_response_code(404);
            echo json_encode(['error' => 'Item no encontrado']);
        }
    } catch (Exception $e) {
        ob_clean();
        http_response_code(500);
        echo json_encode(['error' => 'Error al eliminar de la base de datos: ' . $e->getMessage()]);
    }
    exit;
}

ob_clean();
http_response_code(404);
echo json_encode(['error' => 'Endpoint no encontrado']);
?>
