defmodule LivebookWeb.AppLive do
  use LivebookWeb, :live_view

  import LivebookWeb.AppComponents

  @impl true
  def mount(%{"slug" => slug}, _session, socket) when not socket.assigns.app_authenticated? do
    if connected?(socket) do
      {:ok, push_navigate(socket, to: ~p"/apps/#{slug}/authenticate")}
    else
      {:ok, socket}
    end
  end

  def mount(%{"slug" => slug}, _session, socket) when not socket.assigns.app_authorized? do
    if connected?(socket) do
      Livebook.Teams.Broadcasts.subscribe(:app_deployments)
    end

    {:ok, app} = Livebook.Apps.fetch_app(slug)
    {:ok, assign(socket, app: app), layout: false}
  end

  def mount(%{"slug" => slug}, _session, socket) do
    if socket.assigns.app_settings.multi_session do
      {:ok, app} = Livebook.Apps.fetch_app(slug)

      if connected?(socket) do
        Livebook.App.subscribe(slug)
        Livebook.Teams.Broadcasts.subscribe(:app_deployments)
      end

      {:ok, assign(socket, app: app)}
    else
      {:ok, pid} = Livebook.Apps.fetch_pid(slug)
      session_id = Livebook.App.get_session_id(pid, user: socket.assigns.current_user)
      {:ok, push_navigate(socket, to: ~p"/apps/#{slug}/sessions/#{session_id}")}
    end
  end

  @impl true
  def render(assigns) when assigns.app_authenticated? and assigns.app_authorized? do
    ~H"""
    <div class="h-full relative overflow-y-auto px-4 md:px-20">
      <div class="w-full max-w-screen-lg py-4 mx-auto">
        <div class="absolute md:fixed right-8 md:left-4 top-3 w-10 h-10">
          <.link navigate={~p"/"}>
            <img src={~p"/images/logo.png"} height="40" widthz="40" alt="logo livebook" />
          </.link>
        </div>
        <div class="flex items-center pb-4 mb-2 space-x-4 border-b border-gray-200 pr-20 md:pr-0">
          <h1 class="text-3xl font-semibold text-gray-800">
            {@app.notebook_name}
          </h1>
        </div>
        <div class="pt-4 flex flex-col space-y-16">
          <.content_skeleton :for={_idx <- 1..5} empty={false} />
        </div>
      </div>
    </div>

    <.modal id="sessions-modal" show width="big" patch={~p"/apps"}>
      <div class="flex flex-col space-y-3">
        <h3 class="text-2xl font-semibold text-gray-800">
          {@app.notebook_name}
        </h3>
        <p class="text-gray-700">
          <%= if @app_settings.show_existing_sessions do %>
            This is a multi-session app, pick an existing session or create a new one.
          <% else %>
            This is a multi-session app, create a new one to get started.
          <% end %>
        </p>
        <div class="flex justify-end">
          <.button outlined patch={~p"/apps/#{@app.slug}/new"}>
            <.remix_icon icon="add-line" />
            <span>New session</span>
          </.button>
        </div>
        <div :if={@app_settings.show_existing_sessions} class="w-full flex flex-col space-y-4">
          <.link
            :for={app_session <- active_sessions(@app.sessions)}
            navigate={~p"/apps/#{@app.slug}/sessions/#{app_session.id}"}
            class="px-4 py-3 border border-gray-200 rounded-xl text-gray-800 pointer hover:bg-gray-50 flex justify-between"
          >
            <span>
              Started
              <span :if={app_session.started_by}>
                by <span class="font-semibold">{app_session.started_by.name || "Anonymous"}</span>
              </span>
              {LivebookWeb.HTMLHelpers.format_datetime_relatively(app_session.created_at)} ago
            </span>
            <div class="mr-0.5 flex">
              <.app_status status={app_session.app_status} show_label={false} />
            </div>
          </.link>
        </div>
      </div>
    </.modal>
    """
  end

  def render(assigns) when not assigns.app_authorized? do
    ~H"""
    <LivebookWeb.ErrorHTML.error_page
      status={401}
      title="Not authorized"
      details="You don't have permission to access this app"
    />
    """
  end

  def render(assigns), do: auth_placeholder(assigns)

  @impl true
  def handle_params(_params, _url, socket) when socket.assigns.live_action == :new_session do
    session_id =
      Livebook.App.get_session_id(socket.assigns.app.pid, user: socket.assigns.current_user)

    {:noreply,
     push_navigate(socket, to: ~p"/apps/#{socket.assigns.app.slug}/sessions/#{session_id}")}
  end

  def handle_params(_params, _url, socket), do: {:noreply, socket}

  @impl true
  def handle_info({:app_updated, app}, socket) do
    {:noreply, assign(socket, :app, app)}
  end

  def handle_info(
        {:app_deployment_updated, %{slug: slug}},
        %{assigns: %{app: %{slug: slug} = app}} = socket
      ) do
    if socket.assigns.app_authorized? and
         Livebook.Apps.authorized?(app, socket.assigns.current_user) do
      {:noreply, socket}
    else
      {:noreply, redirect(socket, to: ~p"/apps/#{slug}")}
    end
  end

  def handle_info(_message, socket), do: {:noreply, socket}

  defp active_sessions(sessions) do
    Enum.filter(sessions, &(&1.app_status.lifecycle == :active))
  end
end
