using UnityEngine; using UnityEngine.Networking; using System; using System.Collections; using System.Collections.Generic; public class SupabaseEventLogger : MonoBehaviour { public static SupabaseEventLogger Instance; [Header("Supabase")] public string supabaseUrl = "https://vihjspljbslozbjzxutl.supabase.co"; public string supabaseAnonKey = "YOUR_ANON_KEY_HERE"; private DateTime sessionStartTime; private void Awake() { if (Instance == null) Instance = this; else Destroy(gameObject); } [Serializable] public class GameEventPayload { public string event_key; public string timestamp; public string user_id; } [Serializable] public class GameAttemptPayload { public string game_id; public string scenario_id; public string user_id; public int attempt_number; public string start_timestamp; public string end_timestamp; public int duration_seconds; public float final_score_percentage; public bool pass_fail_status; public int optimal_decisions_count; public int suboptimal_decisions_count; public string key_decisions_log; } [Serializable] public class Decision { public string decisionId; public string timestamp; public bool optimal; } [Serializable] public class DecisionLogWrapper { public List decisions; } public void StartSession() { sessionStartTime = DateTime.UtcNow; GameEventPayload payload = new GameEventPayload { event_key = "game_session_started", timestamp = sessionStartTime.ToString("o"), user_id = "user123" }; StartCoroutine(PostToSupabase("game_events", JsonUtility.ToJson(payload))); } public void LogDecisionEvent(bool isOptimal) { string eventKey = isOptimal ? "game_optimal_decision_made" : "game_suboptimal_decision_made"; GameEventPayload payload = new GameEventPayload { event_key = eventKey, timestamp = DateTime.UtcNow.ToString("o"), user_id = "user123" }; StartCoroutine(PostToSupabase("game_events", JsonUtility.ToJson(payload))); } public void CompleteSessionAndSubmitResult(string userId, bool passed, int optimal, int suboptimal, string scenarioId, List decisionLog = null) { var endTime = DateTime.UtcNow; int duration = (int)(endTime - sessionStartTime).TotalSeconds; // Submit game_session_completed event GameEventPayload completedEvent = new GameEventPayload { event_key = "game_session_completed", timestamp = endTime.ToString("o"), user_id = userId }; StartCoroutine(PostToSupabase("game_events", JsonUtility.ToJson(completedEvent))); // Submit game_score_recorded event GameEventPayload scoreEvent = new GameEventPayload { event_key = "game_score_recorded", timestamp = endTime.ToString("o"), user_id = userId }; StartCoroutine(PostToSupabase("game_events", JsonUtility.ToJson(scoreEvent))); // Submit final game attempt data GameAttemptPayload attempt = new GameAttemptPayload { game_id = "phishing-awareness-1", scenario_id = scenarioId, user_id = userId, attempt_number = 1, start_timestamp = sessionStartTime.ToString("o"), end_timestamp = endTime.ToString("o"), duration_seconds = duration, final_score_percentage = passed ? 100 : 50, pass_fail_status = passed, optimal_decisions_count = optimal, suboptimal_decisions_count = suboptimal, key_decisions_log = decisionLog != null ? JsonUtility.ToJson(new DecisionLogWrapper { decisions = decisionLog }) : "[]" }; StartCoroutine(PostToSupabase("phishing_game_attempts", JsonUtility.ToJson(attempt))); } private IEnumerator PostToSupabase(string table, string jsonBody) { string url = $"{supabaseUrl}/rest/v1/{table}"; UnityWebRequest request = new UnityWebRequest(url, "POST"); byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonBody); request.uploadHandler = new UploadHandlerRaw(bodyRaw); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); request.SetRequestHeader("apikey", supabaseAnonKey); request.SetRequestHeader("Authorization", "Bearer " + supabaseAnonKey); request.SetRequestHeader("Prefer", "return=representation"); yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) { Debug.Log($"✅ Supabase POST to {table}: " + request.downloadHandler.text); } else { Debug.LogError($"❌ Supabase POST Failed ({table}): {request.responseCode}\n{request.error}\n{request.downloadHandler.text}"); } } } //using UnityEngine; //using System; //using System.Collections; //using System.Collections.Generic; //using System.Threading.Tasks; //using Supabase; //using Postgrest.Models; //using Postgrest.Attributes; //using static SupabaseTestInsert; //[Table("game_events")] //public class GameEvent : BaseModel //{ // [PrimaryKey("id", false)] // public Guid Id { get; set; } // [Column("event_key")] // public string EventKey { get; set; } // [Column("timestamp")] // public DateTime Timestamp { get; set; } // [Column("user_id")] // public string UserId { get; set; } //} //[Table("phishing_game_attempts")] //public class GameAttempt : BaseModel //{ // [PrimaryKey("id", false)] // public Guid Id { get; set; } = Guid.NewGuid(); // [Column("game_id")] // public string GameId { get; set; } // [Column("scenario_id")] // public string ScenarioId { get; set; } // [Column("user_id")] // public string UserId { get; set; } // [Column("attempt_number")] // public int AttemptNumber { get; set; } // [Column("start_timestamp")] // public DateTime StartTime { get; set; } // [Column("end_timestamp")] // public DateTime EndTime { get; set; } // [Column("duration_seconds")] // public int DurationSeconds { get; set; } // [Column("final_score_percentage")] // public float Score { get; set; } // [Column("pass_fail_status")] // public bool Passed { get; set; } // [Column("optimal_decisions_count")] // public int Optimal { get; set; } // [Column("suboptimal_decisions_count")] // public int Suboptimal { get; set; } // [Column("key_decisions_log")] // public string KeyDecisionsLogJson { get; set; } //} //public class SupabaseEventLogger : MonoBehaviour //{ // public static SupabaseEventLogger Instance; // private DateTime sessionStartTime; // private void Awake() // { // if (Instance == null) // Instance = this; // else // Destroy(gameObject); // } // public void StartSession() // { // StartCoroutine(StartSessionCoroutine()); // } // private IEnumerator StartSessionCoroutine() // { // var task = StartSessionAsync(); // while (!task.IsCompleted) // yield return null; // if (task.Exception != null) // Debug.LogError("❌ Supabase Error: " + task.Exception.InnerException?.Message); // } // private async Task StartSessionAsync() // { // sessionStartTime = DateTime.UtcNow; // var gameEvent = new GameEvent // { // Id = Guid.NewGuid(), // EventKey = "game_session_started", // Timestamp = sessionStartTime, // UserId = "user123" // }; // await Client.Instance.From().Insert(gameEvent); // Debug.Log("✅ Supabase Event: game_session_started"); // } // public void LogDecisionEvent(bool isOptimal) // { // StartCoroutine(LogDecisionCoroutine(isOptimal)); // } // private IEnumerator LogDecisionCoroutine(bool isOptimal) // { // var task = LogDecisionAsync(isOptimal); // while (!task.IsCompleted) // yield return null; // if (task.Exception != null) // Debug.LogError("❌ Supabase Error: " + task.Exception.InnerException?.Message); // } // private async Task LogDecisionAsync(bool isOptimal) // { // string eventKey = isOptimal ? "game_optimal_decision_made" : "game_suboptimal_decision_made"; // var gameEvent = new GameEvent // { // Id = Guid.NewGuid(), // EventKey = eventKey, // Timestamp = DateTime.UtcNow, // UserId = "user123" // }; // await Client.Instance.From().Insert(gameEvent); // Debug.Log($"✅ Supabase Event: {eventKey}"); // } // public void CompleteSessionAndSubmitResult(string userId, bool passed, int optimal, int suboptimal, string scenarioId, List decisionLog = null) // { // StartCoroutine(CompleteSessionCoroutine(userId, passed, optimal, suboptimal, scenarioId, decisionLog)); // } // private IEnumerator CompleteSessionCoroutine(string userId, bool passed, int optimal, int suboptimal, string scenarioId, List decisionLog) // { // var task = CompleteSessionAsync(userId, passed, optimal, suboptimal, scenarioId, decisionLog); // while (!task.IsCompleted) // yield return null; // if (task.Exception != null) // Debug.LogError("❌ Supabase Error: " + task.Exception.InnerException?.Message); // } // private async Task CompleteSessionAsync(string userId, bool passed, int optimal, int suboptimal, string scenarioId, List decisionLog) // { // var endTime = DateTime.UtcNow; // int duration = (int)(endTime - sessionStartTime).TotalSeconds; // await Client.Instance.From().Insert(new GameEvent // { // Id = Guid.NewGuid(), // EventKey = "game_session_completed", // Timestamp = endTime, // UserId = userId // }); // await Client.Instance.From().Insert(new GameEvent // { // Id = Guid.NewGuid(), // EventKey = "game_score_recorded", // Timestamp = endTime, // UserId = userId // }); // var gameAttempt = new GameAttempt // { // Id = Guid.NewGuid(), // GameId = "phishing-awareness-1", // ScenarioId = scenarioId, // UserId = userId, // AttemptNumber = 1, // StartTime = sessionStartTime, // EndTime = endTime, // DurationSeconds = duration, // Score = passed ? 100 : 50, // Passed = passed, // Optimal = optimal, // Suboptimal = suboptimal, // KeyDecisionsLogJson = decisionLog != null ? JsonUtility.ToJson(new DecisionLogWrapper { decisions = decisionLog }) : "[]" // }; // await Client.Instance.From().Insert(gameAttempt); // Debug.Log("✅ Supabase Game Result Submitted"); // } // [Serializable] // public class Decision // { // public string decisionId; // public string timestamp; // public bool optimal; // } // [Serializable] // public class DecisionLogWrapper // { // public List decisions; // } //} ////using UnityEngine; ////using System; ////using System.Collections.Generic; ////using System.Threading.Tasks; ////using Supabase; // Make sure SupabaseManager initializes this correctly ////using Postgrest.Models; ////using Postgrest.Attributes; ////public class SupabaseEventLogger : MonoBehaviour ////{ //// public static SupabaseEventLogger Instance; //// private DateTime sessionStartTime; //// private void Awake() //// { //// if (Instance == null) //// Instance = this; //// else //// Destroy(gameObject); //// } //// /// //// /// Call this at the start of the game session. //// /// //// public async void StartSession() //// { //// sessionStartTime = DateTime.UtcNow; //// var gameEvent = new GameEvent //// { //// Id = Guid.NewGuid(), // <== Ensure this is explicitly set //// EventKey = "game_session_started", //// Timestamp = sessionStartTime, //// UserId = "user123" //// }; //// await Client.Instance.From().Insert(gameEvent); //// Debug.Log("✅ Supabase Event: game_session_started"); //// } //// /// //// /// Logs optimal/suboptimal decisions at runtime. //// /// //// public async void LogDecisionEvent(bool isOptimal) //// { //// string eventKey = isOptimal ? "game_optimal_decision_made" : "game_suboptimal_decision_made"; //// var gameEvent = new GameEvent //// { //// Id = Guid.NewGuid(), //// EventKey = eventKey, //// Timestamp = DateTime.UtcNow, //// UserId = "user123" //// }; //// await Client.Instance.From().Insert(gameEvent); //// Debug.Log($"✅ Supabase Event: {eventKey}"); //// } //// /// //// /// Completes the session and submits full results to phishing_game_attempts table. //// /// //// public async void CompleteSessionAndSubmitResult(string userId, bool passed, int optimal, int suboptimal, string scenarioId, List decisionLog = null) //// { //// var endTime = DateTime.UtcNow; //// int duration = (int)(endTime - sessionStartTime).TotalSeconds; //// // Log completion events //// await Client.Instance.From().Insert(new GameEvent //// { //// Id = Guid.NewGuid(), //// EventKey = "game_session_completed", //// Timestamp = endTime, //// UserId = userId //// }); //// await Client.Instance.From().Insert(new GameEvent //// {Id = Guid.NewGuid(), //// EventKey = "game_score_recorded", //// Timestamp = endTime, //// UserId = userId //// }); //// // Insert session result //// var gameAttempt = new GameAttempt //// { //// GameId = "phishing-awareness-1", //// ScenarioId = scenarioId, //// UserId = userId, //// AttemptNumber = 1, //// StartTime = sessionStartTime, //// EndTime = endTime, //// DurationSeconds = duration, //// Score = passed ? 100 : 50, //// Passed = passed, //// Optimal = optimal, //// Suboptimal = suboptimal, //// KeyDecisionsLogJson = decisionLog != null ? JsonUtility.ToJson(new DecisionLogWrapper { decisions = decisionLog }) : "[]" //// }; //// await Client.Instance.From().Insert(gameAttempt); //// Debug.Log("✅ Supabase Game Result Submitted"); //// } //// [Serializable] //// public class Decision //// { //// public string decisionId; //// public string timestamp; //// public bool optimal; //// } //// [Serializable] //// public class DecisionLogWrapper //// { //// public List decisions; //// } ////} ////// Existing SupabaseEventLogger class here... ////// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ ////[Table("game_events")] ////public class GameEvent : BaseModel ////{ //// [PrimaryKey("id", false)] //// public Guid Id { get; set; } //// [Column("event_key")] //// public string EventKey { get; set; } //// [Column("timestamp")] //// public DateTime Timestamp { get; set; } //// [Column("user_id")] //// public string UserId { get; set; } ////} ////[Table("phishing_game_attempts")] ////public class GameAttempt : BaseModel ////{ //// [PrimaryKey("id", false)] //// public Guid Id { get; set; } = Guid.NewGuid(); //// [Column("game_id")] //// public string GameId { get; set; } //// [Column("scenario_id")] //// public string ScenarioId { get; set; } //// [Column("user_id")] //// public string UserId { get; set; } //// [Column("attempt_number")] //// public int AttemptNumber { get; set; } //// [Column("start_timestamp")] //// public DateTime StartTime { get; set; } //// [Column("end_timestamp")] //// public DateTime EndTime { get; set; } //// [Column("duration_seconds")] //// public int DurationSeconds { get; set; } //// [Column("final_score_percentage")] //// public float Score { get; set; } //// [Column("pass_fail_status")] //// public bool Passed { get; set; } //// [Column("optimal_decisions_count")] //// public int Optimal { get; set; } //// [Column("suboptimal_decisions_count")] //// public int Suboptimal { get; set; } //// [Column("key_decisions_log")] //// public string KeyDecisionsLogJson { get; set; } ////}