from flask import abort, Blueprint, g, redirect, render_template, request, url_for
 
-from . import auth, db
+from . import auth, comments, db
 from .sanitize import sanitize_user_text
 
 bp = Blueprint("jams", __name__, url_prefix="/jams")
 
 @bp.get("/<int:jamid>")
 def jam(jamid):
-    row = db.query(
-            """
-            SELECT * FROM jams
-            INNER JOIN users ON jams.ownerid = users.userid
-            WHERE jamid = ?
-            """, [jamid], expect_one=True)
-
-    jam = Jam.from_row(row)
+    jam = get_jam_by_id(jamid)
     # Show the main jam page
     return render_template("jam.html", jam=jam)
 
 @jam_owner_only
 def events_create(jamid):
     # Create a new event and redirect to the edit form
-    ...
+    threadid = comments.create_thread(comments.ThreadType.JAM_EVENT, g.userid)
+    timestamp = datetime.now(timezone.utc).isoformat()
+    row = db.query(
+            """
+            INSERT INTO jam_events (jamid, threadid, created, title)
+            VALUES (?, ?, ?, ?)
+            RETURNING eventid
+            """, [jamid, threadid, timestamp, "New Event"], one=True)
+    db.commit()
+
+    eventid = row["eventid"]
+    return redirect(url_for("jams.events_view", jamid=jamid, eventid=eventid))
 
 
 @bp.get("/<int:jamid>/events/<int:eventid>")
 def events_view(jamid, eventid):
     # Show the event page
-    ...
+    jam = get_jam_by_id(jamid)
+    try:
+        event = next(e for e in jam.events if e.eventid == eventid)
+    except StopIteration:
+        abort(404)  # No event with this ID
+
+    return render_template("jam-event.html", jam=jam, event=event)
 
 
 @bp.post("/<int:jamid>/events/<int:eventid>/update")
     # Delete an event, redirect to list of all events
     ...
 
+def get_jam_by_id(jamid):
+    row = db.query(
+            """
+            SELECT * FROM jams
+            INNER JOIN users ON jams.ownerid = users.userid
+            WHERE jamid = ?
+            """, [jamid], expect_one=True)
+    return Jam.from_row(row)
 
 @dataclass
 class Jam:
                 threadid=row["threadid"],
                 created=datetime.fromisoformat(row["created"]),
                 title=row["title"],
-                startdate=datetime.fromisoformat(row["startdate"]),
-                enddate=datetime.fromisoformat(row["enddate"]),
+                startdate=datetime.fromisoformat(row["startdate"]) if "startdate" in row else None,
+                enddate=datetime.fromisoformat(row["enddate"]) if "enddate" in row else None,
                 description=sanitize_user_text(row["description"] or ""),
                 jam_title=row["jam_title"],
                 jam_ownername=row["jam_ownername"],
 
     client.get("/jams/create")
     return 1
 
+# Jams #########################################################################
+
 def test_view_invalid_jam(client):
     response = client.get("/jams/1")
     assert response.status_code == 404
     assert response.request.path == "/jams/1"
     assert b"New Jam" in response.data
 
+def test_create_jam_not_logged_in(client):
+    response = client.get("/jams/create", follow_redirects=True)
+    assert response.request.path == "/login"
+
 def test_jams_list(client, user, jam):
     response = client.get("/jams")
     assert response.status_code == 200
     assert b"Coolest Jam" in response.data
     assert b"pb and jam" in response.data
 
+def test_update_jam_not_logged_in(client):
+    response = client.post("/jams/1/update", follow_redirects=True)
+    assert response.request.path == "/login"
+
 def test_update_invalid_jam(client, user):
     response = client.post(
             "/jams/1/update",
     response = client.get(f"/jams/{jam}")
     assert response.status_code == 404
 
+def test_delete_jam_not_logged_in(client):
+    response = client.get("/jams/1/delete", follow_redirects=True)
+    assert response.request.path == "/login"
+
 def test_delete_invalid_jam(client, user):
     response = client.get("/jams/1/delete")
     assert response.status_code == 404
     create_user(client, "otheruser", login=True)
     response = client.get(f"/jams/{jam}/delete")
     assert response.status_code == 403
+
+# Jam Events ###################################################################
+
+def test_view_event_invalid_jamid(client, user):
+    response = client.get("/jams/1/events/1")
+    assert response.status_code == 404
+
+def test_view_event_invalid_eventid(client, user, jam):
+    response = client.get(f"/jams/{jam}/events/1")
+    assert response.status_code == 404
+
+def test_create_event(client, user, jam):
+    response = client.get(f"/jams/{jam}/events/create", follow_redirects=True)
+    assert response.request.path == f"/jams/{jam}/events/1"
+    assert b"New Event" in response.data
+
+def test_create_event_not_logged_in(client, user, jam):
+    response = client.get("/logout")
+    response = client.get(f"/jams/{jam}/events/create", follow_redirects=True)
+    assert response.request.path == "/login"
+
+def test_create_event_on_other_users_jam(client, user, jam):
+    create_user(client, "otheruser", login=True)
+    response = client.get(f"/jams/{jam}/events/create", follow_redirects=True)
+    assert response.status_code == 403
+
+# Update event
+# Update event invalid event
+# Update event not logged in
+# Update event other users jam
+
+# Delete event
+# Delete event not logged in
+# Delete event invalid event
+# Delete event other users jam
+