defmodule PrymnWeb.Terminal do
  use PrymnWeb, :live_component

  @impl true
  def mount(socket) do
    {:ok, assign(socket, :open, false)}
  end

  @impl true
  def update(assigns, socket) do
    socket =
      if assigns[:data],
        do: push_event(socket, "data", %{"data" => assigns[:data]}),
        else: socket

    {:ok, assign(socket, assigns)}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div>
      <PrymnWeb.Button.primary
        :if={not @open}
        type="button"
        phx-target={@myself}
        phx-click="open_terminal"
      >
        Open Terminal
      </PrymnWeb.Button.primary>
      <PrymnWeb.Button.primary
        :if={@open}
        type="button"
        phx-target={@myself}
        phx-click="close_terminal"
      >
        Close Terminal
      </PrymnWeb.Button.primary>
      <div :if={@open} class="mt-2 bg-black p-2">
        <div phx-hook="Terminal" id="terminal" />
      </div>
    </div>
    """
  end

  @impl true
  def handle_event("open_terminal", _params, socket) do
    # agent = Prymn.Agents.from_server(socket.assigns.server)
    # pid = self()

    # Task.Supervisor.start_child(Prymn.TaskSupervisor, fn ->
    #   # FIXME: Have to wrap this in a Task because gun sends unsolicited messages
    #   # to calling process
    #   stream = Prymn.Agents.terminal(agent)

    #   {:ok, mux_pid} =
    #     Task.Supervisor.start_child(Prymn.TaskSupervisor, fn -> receive_loop(stream) end)

    #   send_update(pid, PrymnWeb.Terminal, id: "terminal", mux_pid: mux_pid, open: true)

    #   case GRPC.Stub.recv(stream, timeout: :infinity) do
    #     {:ok, stream} ->
    #       Enum.map(stream, fn
    #         {:ok, %{output: data}} ->
    #           send(mux_pid, :data)
    #           send_update(pid, PrymnWeb.Terminal, id: "terminal", data: data)

    #         {:error, _err} ->
    #           send_update(pid, PrymnWeb.Terminal, id: "terminal", open: false)
    #       end)

    #     {:error, error} ->
    #       dbg(error)
    #   end
    # end)

    {:noreply, socket}
  end

  def handle_event("close_terminal", _params, socket) do
    send(socket.assigns.mux_pid, :close)
    {:noreply, assign(socket, :open, false)}
  end

  def handle_event("data_event", data, socket) when is_binary(data) do
    send(socket.assigns.mux_pid, {:data_event, data})
    {:noreply, socket}
  end

  def handle_event("resize_event", %{"cols" => cols, "rows" => rows}, socket) do
    send(socket.assigns.mux_pid, {:resize_event, rows, cols})
    {:noreply, socket}
  end

  # defp receive_loop(stream) do
  #   receive do
  #     {:data_event, data} ->
  #       GRPC.Stub.send_request(stream, %TerminalRequest{input: data})
  #       receive_loop(stream)

  #     {:resize_event, rows, cols} ->
  #       GRPC.Stub.send_request(stream, %TerminalRequest{
  #         resize: %TerminalRequest.Resize{rows: rows, cols: cols}
  #       })

  #       receive_loop(stream)

  #     :data ->
  #       receive_loop(stream)

  #     :close ->
  #       GRPC.Stub.send_request(stream, %TerminalRequest{input: ""}, end_stream: true)
  #   after
  #     120_000 ->
  #       GRPC.Stub.send_request(stream, %TerminalRequest{input: ""}, end_stream: true)
  #   end
  # end
end