# This file generated by `dagger_codegen`. Please DO NOT EDIT.
defmodule Dagger.Service do
  @moduledoc """
  A content-addressed service providing TCP connectivity.
  """

  use Dagger.Core.Base, kind: :object, name: "Service"

  alias Dagger.Core.Client
  alias Dagger.Core.QueryBuilder, as: QB

  @derive Dagger.ID
  @derive Dagger.Sync
  defstruct [:query_builder, :client]

  @type t() :: %__MODULE__{}

  @doc """
  Retrieves an endpoint that clients can use to reach this container.

  If no port is specified, the first exposed port is used. If none exist an error is returned.

  If a scheme is specified, a URL is returned. Otherwise, a host:port pair is returned.
  """
  @spec endpoint(t(), [{:port, integer() | nil}, {:scheme, String.t() | nil}]) ::
          {:ok, String.t()} | {:error, term()}
  def endpoint(%__MODULE__{} = service, optional_args \\ []) do
    query_builder =
      service.query_builder
      |> QB.select("endpoint")
      |> QB.maybe_put_arg("port", optional_args[:port])
      |> QB.maybe_put_arg("scheme", optional_args[:scheme])

    Client.execute(service.client, query_builder)
  end

  @doc """
  Retrieves a hostname which can be used by clients to reach this container.
  """
  @spec hostname(t()) :: {:ok, String.t()} | {:error, term()}
  def hostname(%__MODULE__{} = service) do
    query_builder =
      service.query_builder |> QB.select("hostname")

    Client.execute(service.client, query_builder)
  end

  @doc """
  A unique identifier for this Service.
  """
  @spec id(t()) :: {:ok, Dagger.ServiceID.t()} | {:error, term()}
  def id(%__MODULE__{} = service) do
    query_builder =
      service.query_builder |> QB.select("id")

    Client.execute(service.client, query_builder)
  end

  @doc """
  Retrieves the list of ports provided by the service.
  """
  @spec ports(t()) :: {:ok, [Dagger.Port.t()]} | {:error, term()}
  def ports(%__MODULE__{} = service) do
    query_builder =
      service.query_builder |> QB.select("ports") |> QB.select("id")

    with {:ok, items} <- Client.execute(service.client, query_builder) do
      {:ok,
       for %{"id" => id} <- items do
         %Dagger.Port{
           query_builder:
             QB.query()
             |> QB.select("loadPortFromID")
             |> QB.put_arg("id", id),
           client: service.client
         }
       end}
    end
  end

  @doc """
  Start the service and wait for its health checks to succeed.

  Services bound to a Container do not need to be manually started.
  """
  @spec start(t()) :: {:ok, Dagger.Service.t()} | {:error, term()}
  def start(%__MODULE__{} = service) do
    query_builder =
      service.query_builder |> QB.select("start")

    with {:ok, id} <- Client.execute(service.client, query_builder) do
      {:ok,
       %Dagger.Service{
         query_builder:
           QB.query()
           |> QB.select("loadServiceFromID")
           |> QB.put_arg("id", id),
         client: service.client
       }}
    end
  end

  @doc """
  Stop the service.
  """
  @spec stop(t(), [{:kill, boolean() | nil}]) :: {:ok, Dagger.Service.t()} | {:error, term()}
  def stop(%__MODULE__{} = service, optional_args \\ []) do
    query_builder =
      service.query_builder |> QB.select("stop") |> QB.maybe_put_arg("kill", optional_args[:kill])

    with {:ok, id} <- Client.execute(service.client, query_builder) do
      {:ok,
       %Dagger.Service{
         query_builder:
           QB.query()
           |> QB.select("loadServiceFromID")
           |> QB.put_arg("id", id),
         client: service.client
       }}
    end
  end

  @doc """
  Forces evaluation of the pipeline in the engine.
  """
  @spec sync(t()) :: {:ok, Dagger.Service.t()} | {:error, term()}
  def sync(%__MODULE__{} = service) do
    query_builder =
      service.query_builder |> QB.select("sync")

    with {:ok, id} <- Client.execute(service.client, query_builder) do
      {:ok,
       %Dagger.Service{
         query_builder:
           QB.query()
           |> QB.select("loadServiceFromID")
           |> QB.put_arg("id", id),
         client: service.client
       }}
    end
  end

  @spec terminal(t(), [{:cmd, [String.t()]}]) :: Dagger.Service.t()
  def terminal(%__MODULE__{} = service, optional_args \\ []) do
    query_builder =
      service.query_builder
      |> QB.select("terminal")
      |> QB.maybe_put_arg("cmd", optional_args[:cmd])

    %Dagger.Service{
      query_builder: query_builder,
      client: service.client
    }
  end

  @doc """
  Creates a tunnel that forwards traffic from the caller's network to this service.
  """
  @spec up(t(), [{:ports, [Dagger.PortForward.t()]}, {:random, boolean() | nil}]) ::
          :ok | {:error, term()}
  def up(%__MODULE__{} = service, optional_args \\ []) do
    query_builder =
      service.query_builder
      |> QB.select("up")
      |> QB.maybe_put_arg("ports", optional_args[:ports])
      |> QB.maybe_put_arg("random", optional_args[:random])

    case Client.execute(service.client, query_builder) do
      {:ok, _} -> :ok
      error -> error
    end
  end

  @doc """
  Configures a hostname which can be used by clients within the session to reach this container.
  """
  @spec with_hostname(t(), String.t()) :: Dagger.Service.t()
  def with_hostname(%__MODULE__{} = service, hostname) do
    query_builder =
      service.query_builder |> QB.select("withHostname") |> QB.put_arg("hostname", hostname)

    %Dagger.Service{
      query_builder: query_builder,
      client: service.client
    }
  end
end

defimpl Jason.Encoder, for: Dagger.Service do
  def encode(service, opts) do
    {:ok, id} = Dagger.Service.id(service)
    Jason.Encode.string(id, opts)
  end
end

defimpl Nestru.Decoder, for: Dagger.Service do
  def decode_fields_hint(_struct, _context, id) do
    {:ok, Dagger.Client.load_service_from_id(Dagger.Global.dag(), id)}
  end
end
