import gleam/list import gleam/option.{type Option, None} import gleam/int import gleam/float pub type StudySession { StudySession(room_id: String, room_name: String, participants: List(Participant), created_at: String, max_participants: Int, focus_orbs: List(FocusOrb)) } pub type Participant { Participant(user_id: String, username: String, focus_level: Float, cards_studied: Int, current_card: Option(String), is_active: Bool, joined_at: String) } pub type FocusOrb { FocusOrb(user_id: String, x: Float, y: Float, brightness: Float, color: String, label: String) } pub type MultiplayerMessage { JoinRoom(user_id: String, username: String) LeaveRoom(user_id: String) UpdateFocusLevel(user_id: String, level: Float) UpdatePosition(user_id: String, x: Float, y: Float) CardCompleted(user_id: String, card_id: String) ChatMessage(user_id: String, message: String, timestamp: String) SyncState(session_state: StudySession) } pub fn create_session(room_id: String, room_name: String) -> StudySession { StudySession(room_id: room_id, room_name: room_name, participants: [], created_at: "2026-03-19T00:00:00Z", max_participants: 10, focus_orbs: []) } pub fn add_participant(session: StudySession, user_id: String, username: String) -> StudySession { let count = list.length(session.participants) case count >= session.max_participants { True -> session False -> { let p = Participant(user_id: user_id, username: username, focus_level: 100.0, cards_studied: 0, current_card: None, is_active: True, joined_at: "2026-03-19T00:00:00Z") StudySession(..session, participants: [p, ..session.participants]) } } } pub fn remove_participant(session: StudySession, user_id: String) -> StudySession { let filtered = list.filter(session.participants, fn(p) { p.user_id != user_id }) StudySession(..session, participants: filtered) } pub fn update_focus_orb(session: StudySession, user_id: String, x: Float, y: Float, brightness: Float) -> StudySession { let new_orb = FocusOrb(user_id: user_id, x: x, y: y, brightness: brightness, color: "#00f2ff", label: user_id) let filtered_orbs = list.filter(session.focus_orbs, fn(o) { o.user_id != user_id }) StudySession(..session, focus_orbs: [new_orb, ..filtered_orbs]) } pub fn broadcast_message(session: StudySession, message: String) -> String { "Broadcasting to " <> int.to_string(list.length(session.participants)) <> " participants: " <> message } pub fn serialize_session_state(session: StudySession) -> String { "{\"room_id\":\"" <> session.room_id <> "\",\"participants\":" <> int.to_string(list.length(session.participants)) <> ",\"focus_orbs\":" <> int.to_string(list.length(session.focus_orbs)) <> "}" } pub fn generate_svg_focus_space(session: StudySession) -> String { let header = "" let orbs = list.fold(session.focus_orbs, "", fn(acc, orb) { acc <> "" }) header <> orbs <> "" } pub fn calculate_group_focus_score(session: StudySession) -> Float { case list.length(session.participants) { 0 -> 0.0 n -> list.fold(session.participants, 0.0, fn(acc, p) { acc +. p.focus_level }) /. int.to_float(n) } } pub fn detect_focus_dip(current: Float, previous: Float) -> Bool { current <. previous *. 0.8 } pub fn send_focus_alert(_user_id: String, username: String) -> String { "Alert for " <> username <> ": Focus dropping" } pub fn track_study_velocity(session: StudySession) -> String { let total = list.fold(session.participants, 0, fn(acc, p) { acc + p.cards_studied }) "Cards studied: " <> int.to_string(total) } pub fn generate_collaboration_report(session: StudySession) -> String { "

" <> session.room_name <> "

" <> int.to_string(list.length(session.participants)) <> " participants

" } pub fn list_active_rooms() -> List(StudySession) { [] } pub fn invite_participant(_session: StudySession, invitee: String) -> String { "Invited " <> invitee }