defmodule SpazioSolazzo.BookingSystem.TimeSlotTemplateTest do use ExUnit.Case, async: true use SpazioSolazzo.DataCase alias SpazioSolazzo.BookingSystem setup do {:ok, space} = BookingSystem.create_space( "Test Space", "test-space", "Test description", 10 ) %{space: space} end describe "create_time_slot_template/4" do test "creates a time slot template successfully", %{space: space} do assert {:ok, slot} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[10:00:00], :monday, space.id ) assert slot.start_time == ~T[09:00:00] assert slot.end_time == ~T[10:00:00] assert slot.day_of_week == :monday assert slot.space_id == space.id end test "creates templates for all days of the week", %{space: space} do days = [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday] for day <- days do assert {:ok, slot} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[10:00:00], day, space.id ) assert slot.day_of_week == day end end test "prevents overlapping time slots on same day", %{space: space} do assert {:ok, _slot1} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[11:00:00], :monday, space.id ) assert {:error, error} = BookingSystem.create_time_slot_template( ~T[10:00:00], ~T[12:00:00], :monday, space.id ) error_messages = Ash.Error.error_descriptions(error) assert String.contains?( error_messages, "time slot overlaps with existing template for this space and day." ) end test "allows same time slot on different days", %{space: space} do assert {:ok, _slot1} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[11:00:00], :monday, space.id ) assert {:ok, slot2} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[11:00:00], :tuesday, space.id ) assert slot2.day_of_week == :tuesday end test "allows adjacent time slots on same day", %{space: space} do assert {:ok, _slot1} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[11:00:00], :monday, space.id ) assert {:ok, slot2} = BookingSystem.create_time_slot_template( ~T[11:00:00], ~T[13:00:00], :monday, space.id ) assert slot2.start_time == ~T[11:00:00] end test "rejects invalid day of week", %{space: space} do assert {:error, error} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[10:00:00], :invalid_day, space.id ) error_messages = Ash.Error.error_descriptions(error) assert String.contains?(error_messages, "atom must be one of") end test "rejects end time before start time", %{space: space} do assert {:error, error} = BookingSystem.create_time_slot_template( ~T[10:00:00], ~T[09:00:00], :monday, space.id ) error_messages = Ash.Error.error_descriptions(error) assert String.contains?(error_messages, "must be after start_time") end test "rejects equal start and end times", %{space: space} do assert {:error, error} = BookingSystem.create_time_slot_template( ~T[10:00:00], ~T[10:00:00], :monday, space.id ) error_messages = Ash.Error.error_descriptions(error) assert String.contains?(error_messages, "must be after start_time") end end describe "get_space_time_slots_by_date/2" do setup %{space: space} do {:ok, monday_morning} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[13:00:00], :monday, space.id ) {:ok, monday_afternoon} = BookingSystem.create_time_slot_template( ~T[14:00:00], ~T[18:00:00], :monday, space.id ) {:ok, tuesday_slot} = BookingSystem.create_time_slot_template( ~T[09:00:00], ~T[13:00:00], :tuesday, space.id ) %{ monday_morning: monday_morning, monday_afternoon: monday_afternoon, tuesday_slot: tuesday_slot } end test "returns time slots for specific date's day of week", %{space: space} do monday_date = ~D[2026-02-02] assert Date.day_of_week(monday_date) == 1 {:ok, slots} = BookingSystem.get_space_time_slots_by_date(space.id, monday_date) assert length(slots) == 2 assert Enum.any?(slots, &(&1.start_time == ~T[09:00:00])) assert Enum.any?(slots, &(&1.start_time == ~T[14:00:00])) end test "returns different slots for different days", %{space: space} do tuesday_date = ~D[2026-02-03] assert Date.day_of_week(tuesday_date) == 2 {:ok, slots} = BookingSystem.get_space_time_slots_by_date(space.id, tuesday_date) assert length(slots) == 1 assert hd(slots).start_time == ~T[09:00:00] end test "returns empty list when no slots for that day", %{space: space} do wednesday_date = ~D[2026-02-04] assert Date.day_of_week(wednesday_date) == 3 {:ok, slots} = BookingSystem.get_space_time_slots_by_date(space.id, wednesday_date) assert slots == [] end test "handles all days of the week correctly", %{space: space} do days_and_dates = [ {:monday, ~D[2026-02-02]}, {:tuesday, ~D[2026-02-03]}, {:wednesday, ~D[2026-02-04]}, {:thursday, ~D[2026-02-05]}, {:friday, ~D[2026-02-06]}, {:saturday, ~D[2026-02-07]}, {:sunday, ~D[2026-02-01]} ] for {day_atom, date} <- days_and_dates do BookingSystem.create_time_slot_template( ~T[20:00:00], ~T[21:00:00], day_atom, space.id ) {:ok, slots} = BookingSystem.get_space_time_slots_by_date(space.id, date) assert Enum.any?(slots, &(&1.start_time == ~T[20:00:00])) end end test "only returns slots for specified space", %{space: space} do {:ok, other_space} = BookingSystem.create_space( "Other Space", "other-space", "Other description", 5 ) {:ok, _other_slot} = BookingSystem.create_time_slot_template( ~T[20:00:00], ~T[22:00:00], :monday, other_space.id ) monday_date = ~D[2026-02-02] {:ok, slots} = BookingSystem.get_space_time_slots_by_date(space.id, monday_date) assert Enum.all?(slots, &(&1.space_id == space.id)) refute Enum.any?(slots, &(&1.start_time == ~T[20:00:00])) end end end