defmodule SpazioSolazzoWeb.SpaceBookingLive do
  use SpazioSolazzoWeb, :live_view

  alias SpazioSolazzo.BookingSystem
  import SpazioSolazzoWeb.BookingComponents

  def mount(%{"space_slug" => space_slug}, _session, socket) do
    case BookingSystem.get_space_by_slug(space_slug) do
      {:ok, space} ->
        selected_date = Date.utc_today()
        current_user = socket.assigns[:current_user]

        time_slots = load_time_slots_with_stats(space, selected_date, current_user)

        if connected?(socket) do
          Phoenix.PubSub.subscribe(SpazioSolazzo.PubSub, "booking:created")
          Phoenix.PubSub.subscribe(SpazioSolazzo.PubSub, "booking:approved")
          Phoenix.PubSub.subscribe(SpazioSolazzo.PubSub, "booking:cancelled")
          Phoenix.PubSub.subscribe(SpazioSolazzo.PubSub, "booking:rejected")
        end

        {:ok,
         socket
         |> assign(
           space: space,
           selected_date: selected_date,
           selected_time_slot: nil,
           show_booking_modal: false,
           show_success_modal: false,
           time_slots: time_slots
         )}

      {:error, _error} ->
        {:ok,
         socket
         |> put_flash(:error, "Space not found")
         |> push_navigate(to: "/")}
    end
  end

  def handle_event("select_slot", %{"time_slot_id" => time_slot_id}, socket) do
    time_slot = Enum.find(socket.assigns.time_slots, &(&1.id == time_slot_id))
    {:noreply, assign(socket, selected_time_slot: time_slot, show_booking_modal: true)}
  end

  def handle_event("cancel_booking", _params, socket) do
    {:noreply, assign(socket, show_booking_modal: false)}
  end

  def handle_event("close_success_modal", _params, socket) do
    {:noreply, assign(socket, show_success_modal: false)}
  end

  def handle_info({:create_booking, booking_data}, socket) do
    case parse_booking_data(booking_data) do
      {:error, error} -> {:noreply, put_flash(socket, :error, error)}
      {:ok, booking_data} -> create_booking(booking_data, socket)
    end
  end

  def handle_info({:date_selected, date}, socket) do
    time_slots =
      load_time_slots_with_stats(socket.assigns.space, date, socket.assigns.current_user)

    {:noreply,
     socket
     |> assign(
       selected_date: date,
       time_slots: time_slots
     )}
  end

  def handle_info(
        %{topic: "booking:" <> _event, payload: %{data: %{space_id: space_id, date: date}}},
        %{assigns: %{space: %{id: space_id}, selected_date: date}} = socket
      ) do
    time_slots =
      load_time_slots_with_stats(socket.assigns.space, date, socket.assigns.current_user)

    {:noreply,
     socket
     |> assign(time_slots: time_slots)}
  end

  def handle_info(_msg, socket) do
    {:noreply, socket}
  end

  defp create_booking(booking_data, socket) do
    current_user = socket.assigns.current_user

    result =
      BookingSystem.create_booking(
        socket.assigns.space.id,
        current_user.id,
        socket.assigns.selected_date,
        socket.assigns.selected_time_slot.start_time,
        socket.assigns.selected_time_slot.end_time,
        booking_data.customer_name,
        current_user.email,
        booking_data.customer_phone,
        booking_data.customer_comment
      )

    case result do
      {:ok, _booking} ->
        {:noreply,
         socket
         |> assign(
           show_booking_modal: false,
           show_success_modal: true
         )}

      {:error, _error} ->
        {:noreply,
         socket
         |> assign(show_booking_modal: false)
         |> put_flash(:error, "Failed to create booking request.")}
    end
  end

  defp parse_booking_data(%{customer_name: ""}) do
    {:error, "Please fill all the required fields to create a booking request."}
  end

  defp parse_booking_data(
         %{
           customer_name: _,
           customer_phone: _,
           customer_comment: _
         } = form
       ) do
    {:ok, form}
  end

  defp load_time_slots_with_stats(space, date, current_user) do
    time_slots =
      BookingSystem.get_space_time_slots_by_date!(space.id, date,
        load: [
          booking_stats: %{
            date: date,
            space_id: space.id,
            capacity: space.capacity,
            user_id: current_user.id
          }
        ]
      )

    Enum.sort_by(time_slots, fn slot -> slot.start_time end)
  end
end
