using Hangfire; using InstaVibe.Hubs; using InstaVibe.Models; using Microsoft.AspNet.SignalR; using System; using System.Collections.Generic; using System.Configuration; using System.Data.SqlClient; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; namespace InstaVibe.Controllers { public class ChatController : Controller { public static string connectionString = ConfigurationManager.ConnectionStrings["InstaVibe"].ConnectionString.ToString(); // GET: Chat public ActionResult Index() { return View(); } public ActionResult Message(int? userId) { if (Session["UserId"] == null) return RedirectToAction("Login", "Account"); int currentUserId = Convert.ToInt32(Session["UserId"]); var users = new List(); using (var con = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(@" SELECT user_id as UserId, fullname as FullName, ISNULL(profile_picture, '/images/default-profile.png') as ProfilePicture, is_online as IsOnline FROM Users WHERE user_id != @currentUserId ORDER BY FullName", con)) { cmd.Parameters.AddWithValue("@currentUserId", currentUserId); con.Open(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { var user = new User { UserId = Convert.ToInt32(reader["UserId"]), FullName = reader["FullName"].ToString(), ProfilePicture = reader["ProfilePicture"].ToString(), IsOnline = Convert.ToBoolean(reader["IsOnline"]), HasUnreadMessages = CheckUnreadMessages(Convert.ToInt32(reader["UserId"]), currentUserId) }; users.Add(user); } } } ViewBag.Users = users; ViewBag.CurrentUserId = currentUserId; ViewBag.ChatUserId = userId; if (userId.HasValue) ViewBag.Messages = LoadMessagesFromDb(currentUserId, userId.Value); return View(); } private List LoadMessagesFromDb(int senderId, int receiverId) { var messages = new List(); using (var con = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(@" SELECT * FROM Messages WHERE (sender_id = @sid AND receiver_id = @rid) OR (sender_id = @rid AND receiver_id = @sid) ORDER BY sent_at ASC", con)) { cmd.Parameters.AddWithValue("@sid", senderId); cmd.Parameters.AddWithValue("@rid", receiverId); con.Open(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { messages.Add(new { Text = reader["message_text"].ToString(), IsSender = Convert.ToInt32(reader["sender_id"]) == senderId, SentAt = Convert.ToDateTime(reader["sent_at"]), MediaUrl = reader["media_url"] as string }); } } } return messages; } private bool CheckUnreadMessages(int senderId, int receiverId) { using (var con = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(@" SELECT COUNT(*) FROM Messages WHERE sender_id=@s AND receiver_id=@r AND is_read=0", con)) { cmd.Parameters.AddWithValue("@s", senderId); cmd.Parameters.AddWithValue("@r", receiverId); con.Open(); return (int)cmd.ExecuteScalar() > 0; } } // Keep existing methods for API calls if needed [HttpGet] public JsonResult GetMessages(int senderId, int receiverId) { var messages = new List(); using (var con = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(@" SELECT * FROM Messages WHERE (sender_id=@sid AND receiver_id=@rid) OR (sender_id=@rid AND receiver_id=@sid) ORDER BY sent_at ASC", con)) { cmd.Parameters.AddWithValue("@sid", senderId); cmd.Parameters.AddWithValue("@rid", receiverId); con.Open(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { messages.Add(new { message_text = reader["message_text"].ToString(), sender_id = Convert.ToInt32(reader["sender_id"]), sent_at = Convert.ToDateTime(reader["sent_at"]).ToString("yyyy-MM-ddTHH:mm:ss"), media_url = reader["media_url"] as string }); } } } return Json(messages, JsonRequestBehavior.AllowGet); } [HttpPost] public JsonResult SendMessage(int senderId, int receiverId, string messageText) { try { DateTime sentAt = DateTime.Now; using (SqlConnection con = new SqlConnection(connectionString)) { string query = @"INSERT INTO Messages (sender_id, receiver_id, message_text, sent_at) VALUES (@senderId, @receiverId, @messageText, @sentAt)"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@senderId", senderId); cmd.Parameters.AddWithValue("@receiverId", receiverId); cmd.Parameters.AddWithValue("@messageText", messageText); cmd.Parameters.AddWithValue("@sentAt", sentAt); con.Open(); cmd.ExecuteNonQuery(); } // JSON response return Json(new { success = true, message = "Message sent successfully", sentAt = sentAt.ToString("yyyy-MM-ddTHH:mm:ss") }, JsonRequestBehavior.DenyGet); } catch (Exception ex) { return Json(new { success = false, message = "Failed to send message: " + ex.Message }, JsonRequestBehavior.DenyGet); } } [HttpPost] public JsonResult SendMedia(int senderId, int receiverId, HttpPostedFileBase uploadedFile) { if (uploadedFile == null || uploadedFile.ContentLength == 0) return Json(new { success = false, message = "No file selected." }); string[] allowed = { ".jpg", ".jpeg", ".png", ".mp4", ".mov", ".pdf", ".doc", ".docx" }; string ext = Path.GetExtension(uploadedFile.FileName).ToLower(); if (!allowed.Contains(ext)) return Json(new { success = false, message = "File type not supported." }); try { string folder = Server.MapPath("~/UserUploads/"); Directory.CreateDirectory(folder); string fileName = Guid.NewGuid() + ext; string fullPath = Path.Combine(folder, fileName); uploadedFile.SaveAs(fullPath); string mediaUrl = "/UserUploads/" + fileName; using (var con = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(@" INSERT INTO Messages (sender_id, receiver_id, message_text, media_url, sent_at) VALUES (@sid,@rid,'',@media,GETDATE())", con)) { cmd.Parameters.AddWithValue("@sid", senderId); cmd.Parameters.AddWithValue("@rid", receiverId); cmd.Parameters.AddWithValue("@media", mediaUrl); con.Open(); cmd.ExecuteNonQuery(); } // Send to both sender and receiver via SignalR var hub = GlobalHost.ConnectionManager.GetHubContext(); hub.Clients.User(receiverId.ToString()).sendMediaMessage(senderId, receiverId, mediaUrl); hub.Clients.User(senderId.ToString()).sendMediaMessage(senderId, receiverId, mediaUrl); // <-- add this line return Json(new { success = true, mediaUrl = mediaUrl }); } catch (Exception ex) { return Json(new { success = false, message = ex.Message }); } } [HttpGet] public JsonResult GetUnreadStatuses(int currentUserId) { List unreadStatuses = new List(); using (SqlConnection con = new SqlConnection(connectionString)) { string query = @"SELECT sender_id, COUNT(*) AS UnreadCount FROM Messages WHERE receiver_id = @currentUserId AND is_read = 0 GROUP BY sender_id"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@currentUserId", currentUserId); con.Open(); using (SqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { unreadStatuses.Add(new { senderId = Convert.ToInt32(reader["sender_id"]), unreadCount = Convert.ToInt32(reader["UnreadCount"]) }); } } } return Json(unreadStatuses, JsonRequestBehavior.AllowGet); } [HttpGet] public JsonResult GetOnlineStatuses(int currentUserId) { List onlineStatuses = new List(); using (SqlConnection con = new SqlConnection(connectionString)) { string query = @"SELECT user_id, is_online FROM Users WHERE user_id != @currentUserId"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@currentUserId", currentUserId); con.Open(); using (SqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { onlineStatuses.Add(new { userId = Convert.ToInt32(reader["user_id"]), isOnline = Convert.ToBoolean(reader["is_online"]) }); } } } return Json(onlineStatuses, JsonRequestBehavior.AllowGet); } [HttpPost] public JsonResult DeleteOldMessages() { int deletedCount = 0; using (SqlConnection con = new SqlConnection(connectionString)) { string query = "DELETE FROM Messages WHERE sent_at < DATEADD(DAY, -1, GETDATE())"; SqlCommand cmd = new SqlCommand(query, con); con.Open(); deletedCount = cmd.ExecuteNonQuery(); } return Json(new { success = true, deleted = deletedCount }); } [HttpGet] public JsonResult GetQuizQuestions() { List questions = new List(); using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); string[] levels = { "Easy", "Medium", "Hard" }; foreach (var level in levels) { string query = "SELECT TOP 5 * FROM QuizQuestions WHERE DifficultyLevel = @level ORDER BY NEWID()"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@level", level); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { questions.Add(new QuizQuestion { QuestionID = Convert.ToInt32(reader["QuestionID"]), QuestionText = reader["QuestionText"].ToString(), OptionA = reader["OptionA"].ToString(), OptionB = reader["OptionB"].ToString(), OptionC = reader["OptionC"].ToString(), OptionD = reader["OptionD"].ToString(), CorrectOption = reader["CorrectOption"].ToString(), DifficultyLevel = reader["DifficultyLevel"].ToString() }); } reader.Close(); } } return Json(questions, JsonRequestBehavior.AllowGet); } public JsonResult SearchUsers(string term) { List results = new List(); using (SqlConnection con = new SqlConnection(connectionString)) { string query = "SELECT user_id, fullname, profile_picture FROM Users WHERE fullname LIKE @term"; SqlCommand cmd = new SqlCommand(query, con); cmd.Parameters.AddWithValue("@term", "%" + term + "%"); con.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { results.Add(new { user_id = (int)reader["user_id"], fullname = reader["fullname"].ToString(), profile_picture = reader["profile_picture"].ToString() }); } } return Json(results, JsonRequestBehavior.AllowGet); } [HttpPost] [ValidateAntiForgeryToken] public JsonResult ScheduleMessage(int ReceiverId, string MessageText, string ScheduledUtc) { try { if (Session["UserId"] == null) return Json(new { success = false, error = "Not authenticated." }); int senderId = Convert.ToInt32(Session["UserId"]); if (ReceiverId == 0 || string.IsNullOrWhiteSpace(MessageText) || string.IsNullOrWhiteSpace(ScheduledUtc)) return Json(new { success = false, error = "Missing fields." }); if (!DateTimeOffset.TryParse(ScheduledUtc, out var parsed)) return Json(new { success = false, error = "Invalid date format." }); var scheduledUtc = parsed.ToUniversalTime(); if (scheduledUtc <= DateTimeOffset.UtcNow.AddSeconds(5)) { scheduledUtc = DateTimeOffset.UtcNow.AddMinutes(1); } int scheduledId; using (var conn = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(@" INSERT INTO ScheduledMessages (sender_id, receiver_id, message_text, scheduled_time, is_sent, created_at) VALUES (@sender, @receiver, @text, @scheduled, 0, GETDATE()); SELECT CAST(SCOPE_IDENTITY() AS INT);", conn)) { cmd.Parameters.AddWithValue("@sender", senderId); cmd.Parameters.AddWithValue("@receiver", ReceiverId); cmd.Parameters.AddWithValue("@text", MessageText); cmd.Parameters.AddWithValue("@scheduled", scheduledUtc.UtcDateTime); conn.Open(); scheduledId = Convert.ToInt32(cmd.ExecuteScalar()); } // Hangfire: schedule job BackgroundJob.Schedule(() => ScheduledMessageProcessor.ProcessScheduledMessage(scheduledId), scheduledUtc); return Json(new { success = true, scheduledId }); } catch (Exception ex) { return Json(new { success = false, error = ex.Message }); } } public static void ProcessScheduledMessage(int messageId) { try { using (var conn = new SqlConnection(connectionString)) { conn.Open(); using (var tx = conn.BeginTransaction()) { // Scheduled message fetch karo bool alreadySent = false; int senderId = 0, receiverId = 0; string messageText = ""; using (var cmd = new SqlCommand(@" SELECT sender_id, receiver_id, message_text, is_sent FROM ScheduledMessages WHERE message_id = @id", conn, tx)) { cmd.Parameters.AddWithValue("@id", messageId); using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) { tx.Commit(); return; } alreadySent = Convert.ToBoolean(reader["is_sent"]); if (alreadySent) { tx.Commit(); return; } senderId = Convert.ToInt32(reader["sender_id"]); receiverId = Convert.ToInt32(reader["receiver_id"]); messageText = reader["message_text"].ToString(); reader.Close(); } } // Messages table me insert karo using (var insertCmd = new SqlCommand(@" INSERT INTO Messages (sender_id, receiver_id, message_text, sent_at) VALUES (@sid, @rid, @msg, GETDATE())", conn, tx)) { insertCmd.Parameters.AddWithValue("@sid", senderId); insertCmd.Parameters.AddWithValue("@rid", receiverId); insertCmd.Parameters.AddWithValue("@msg", messageText); insertCmd.ExecuteNonQuery(); } // ScheduledMessages table me sent=1 update karo using (var updateCmd = new SqlCommand(@" UPDATE ScheduledMessages SET is_sent = 1 WHERE message_id = @id", conn, tx)) { updateCmd.Parameters.AddWithValue("@id", messageId); updateCmd.ExecuteNonQuery(); } tx.Commit(); } } } catch (Exception ex) { } } public void SendScheduledMessages(int receiverId, string message) { using (var conn = new SqlConnection(connectionString)) { conn.Open(); string query = @"INSERT INTO Messages (ReceiverId, MessageText, SentAt) VALUES (@rid, @msg, GETDATE())"; using (var cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@rid", receiverId); cmd.Parameters.AddWithValue("@msg", message); cmd.ExecuteNonQuery(); } } } } }