Skip to main content

lib/mix/tasks/star_view.setup.demo_controller.ex

defmodule Mix.Tasks.StarView.Setup.SearchController.Docs do
  @moduledoc false

  def short_doc(), do: "Generates an example StarView demo controller with Datastar"
  def example(), do: "mix star_view.setup.search_controller"
  def long_doc(), do: "#{short_doc()}"
end

if Code.ensure_loaded?(Igniter) do
  defmodule Mix.Tasks.StarView.Setup.SearchController do
    @shortdoc "#{__MODULE__.Docs.short_doc()}"
    @moduledoc __MODULE__.Docs.long_doc()

    use Igniter.Mix.Task

    @impl Igniter.Mix.Task
    def info(_argv, _composing_task) do
      %Igniter.Mix.Task.Info{
        group: :star_view,
        adds_deps: [],
        installs: [],
        example: __MODULE__.Docs.example(),
        only: nil,
        positional: [],
        composes: [],
        schema: [router: :string],
        defaults: [],
        aliases: [],
        required: []
      }
    end

    @impl Igniter.Mix.Task
    def igniter(igniter) do
      web_module = Igniter.Libs.Phoenix.web_module(igniter)
      endpoint_module = Module.concat(web_module, Endpoint)

      {phoenix?, igniter} = Igniter.Project.Module.module_exists(igniter, endpoint_module)

      igniter
      |> maybe_generate_example(web_module, phoenix?)
      |> maybe_patch_router(web_module, phoenix?)
    end

    defp maybe_generate_example(igniter, web_module, false) do
      module = Module.concat([web_module, StarViewDemo])

      Igniter.Project.Module.create_module(
        igniter,
        module,
        """
        @moduledoc "Example Datastar handler using StarView with Plug."

        def handle_event(conn, "increment", signals) do
          count = Map.get(signals, "count", 0) + 1
          StarView.patch_signals(conn, %{count: count})
        end
        """
      )
    end

    defp maybe_generate_example(igniter, web_module, true) do
      controller = Module.concat([web_module, SearchController])

      template =
        Path.join(:code.priv_dir(:star_view), "templates/search_controller.ex.eex")
        |> EEx.eval_file(assigns: [web_module: web_module, controller: controller])

      Igniter.Project.Module.create_module(igniter, controller, template)
    end

    defp maybe_patch_router(igniter, _web_module, false), do: igniter

    defp maybe_patch_router(igniter, web_module, true) do
      {igniter, router} =
        Igniter.Libs.Phoenix.select_router(
          igniter,
          "Which Phoenix router should StarView add routes to?"
        )

      if router do
        do_patch_router(igniter, web_module, router)
      else
        Igniter.add_warning(igniter, "No Phoenix router found. Skipping route setup.")
      end
    end

    defp do_patch_router(igniter, web_module, router) do
      {_, source, _zipper} = Igniter.Project.Module.find_module!(igniter, router)
      source_str = Rewrite.Source.get(source, :content)

      already_has_ds_route? = String.contains?(source_str, ~s("/ds/:module/:event"))

      if already_has_ds_route? do
        controller = Module.concat([web_module, SearchController])
        already_has_demo? = String.contains?(source_str, "/search")

        if already_has_demo? do
          igniter
        else
          Igniter.Libs.Phoenix.append_to_scope(
            igniter,
            "/",
            "get \"/search\", #{inspect(controller)}, :show\n",
            with_pipelines: [:browser],
            arg2: web_module,
            router: router
          )
        end
      else
        controller = Module.concat([web_module, SearchController])

        route_contents = """
        get "/search", #{inspect(controller)}, :mount
        post "/ds/:module/:event", StarView.Phoenix.Dispatch, []
        """

        Igniter.Libs.Phoenix.append_to_scope(
          igniter,
          "/",
          route_contents,
          with_pipelines: [:browser],
          arg2: web_module,
          router: router
        )
      end
    end
  end
else
  defmodule Mix.Tasks.StarView.Setup.SearchController do
    @shortdoc "#{__MODULE__.Docs.short_doc()} | Install `igniter` to use"
    @moduledoc __MODULE__.Docs.long_doc()
    use Mix.Task

    @impl Mix.Task
    def run(_argv) do
      Mix.shell().error("Requires igniter.")
      exit({:shutdown, 1})
    end
  end
end