'Missing ticket_id']); exit; } // Check access $stmt = db()->prepare("SELECT * FROM tickets WHERE id = ?"); $stmt->execute([$ticketId]); $ticket = $stmt->fetch(); if (!$ticket || $ticket['status'] === 'closed') { echo json_encode(['error' => 'Ticket closed or not found']); exit; } if ($user['role'] === 'user' && $ticket['user_id'] != $user['id']) { echo json_encode(['error' => 'Access denied']); exit; } $filePath = null; $fileName = null; $fileType = null; if ($file && $file['error'] === UPLOAD_ERR_OK) { $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/zip', 'text/plain']; $maxSize = 50 * 1024 * 1024; // 50MB if ($file['size'] > $maxSize) { echo json_encode(['error' => 'File too large (max 50MB)']); exit; } $extension = pathinfo($file['name'], PATHINFO_EXTENSION); $newFileName = bin2hex(random_bytes(16)) . '.' . $extension; $uploadDir = __DIR__ . '/../uploads/'; $targetPath = $uploadDir . $newFileName; if (move_uploaded_file($file['tmp_name'], $targetPath)) { $filePath = 'uploads/' . $newFileName; $fileName = $file['name']; $fileType = $file['type']; } else { echo json_encode(['error' => 'Failed to upload file']); exit; } } $stmt = db()->prepare("INSERT INTO messages (ticket_id, user_id, message, file_path, file_name, file_type) VALUES (?, ?, ?, ?, ?, ?)"); $stmt->execute([$ticketId, $user['id'], $message, $filePath, $fileName, $fileType]); // Update ticket status automatically if helper replies if ($user['role'] !== 'user' && $ticket['status'] === 'open') { $updateStmt = db()->prepare("UPDATE tickets SET status = 'in_progress' WHERE id = ?"); $updateStmt->execute([$ticketId]); } echo json_encode(['success' => true]);