defmodule Mix.Tasks.Raxol.Demo do
  @moduledoc """
  Runs built-in Raxol demo applications.

  ## Usage

      mix raxol.demo              # Interactive demo picker
      mix raxol.demo counter      # Simple counter
      mix raxol.demo todo         # Todo list
      mix raxol.demo dashboard    # Live BEAM dashboard
      mix raxol.demo showcase     # Component showcase
      mix raxol.demo --list       # List available demos

  ## Demos

    * `counter`   - Simple counter with +/- keys and buttons
    * `todo`      - Todo list with add/delete/toggle and input modes
    * `dashboard` - Live BEAM dashboard with scheduler, memory, process stats
    * `showcase`  - Interactive component showcase with 5 tabbed sections
  """

  use Mix.Task

  @shortdoc "Run built-in Raxol demo applications"

  @demos [
    {"counter", Raxol.Demo.Counter, "Simple counter with +/- keys and buttons"},
    {"todo", Raxol.Demo.Todo,
     "Todo list with add/delete/toggle and input modes"},
    {"dashboard", Raxol.Demo.Dashboard,
     "Live BEAM dashboard with scheduler, memory, process stats"},
    {"showcase", Raxol.Demo.Showcase,
     "Interactive component showcase with 5 tabbed sections"}
  ]

  @demo_names Enum.map(@demos, &elem(&1, 0))

  @impl Mix.Task
  def run(args) do
    case OptionParser.parse(args, strict: [list: :boolean]) do
      {opts, [], _} ->
        if Keyword.get(opts, :list, false) do
          print_list()
        else
          prompt_and_run()
        end

      {_opts, [name], _} ->
        launch(name)

      _ ->
        print_usage()
    end
  end

  defp launch(name) do
    case Enum.find(@demos, fn {n, _, _} -> n == name end) do
      {_, module, _} ->
        Mix.Task.run("app.start")

        Mix.shell().info([:green, "Starting #{name} demo...", :reset])
        Mix.shell().info("Press 'q' or Ctrl+C to quit.\n")

        {:ok, pid} = Raxol.start_link(module, [])
        ref = Process.monitor(pid)

        receive do
          {:DOWN, ^ref, :process, ^pid, _reason} -> :ok
        end

      nil ->
        Mix.shell().error("Unknown demo: #{name}")
        Mix.shell().error("Available: #{Enum.join(@demo_names, ", ")}")
    end
  end

  defp prompt_and_run do
    _ = print_demo_menu()

    answer =
      Mix.shell().prompt(
        "Pick a demo [#{Enum.join(@demo_names, "/")}] (default: counter)"
      )
      |> String.trim()
      |> String.downcase()

    launch(resolve_demo_name(answer))
  end

  defp print_demo_menu do
    Mix.shell().info("")
    Mix.shell().info([:bright, "Available demos:", :reset])

    for {{name, _, desc}, idx} <- Enum.with_index(@demos, 1) do
      Mix.shell().info("  #{idx}. #{String.pad_trailing(name, 12)} #{desc}")
    end
  end

  defp resolve_demo_name(""), do: "counter"

  defp resolve_demo_name(n) when n in ["1", "2", "3", "4"],
    do: Enum.at(@demo_names, String.to_integer(n) - 1)

  defp resolve_demo_name(n) when n in @demo_names, do: n

  defp resolve_demo_name(_) do
    Mix.shell().info([:yellow, "Unknown demo, using counter.", :reset])
    "counter"
  end

  defp print_list do
    Mix.shell().info([:bright, "Available demos:", :reset])
    Mix.shell().info("")

    for {name, _, desc} <- @demos do
      label = String.pad_trailing(name, 12)
      Mix.shell().info(["  ", :cyan, label, :reset, desc])
    end

    Mix.shell().info("")
    Mix.shell().info("Usage: mix raxol.demo NAME")
  end

  defp print_usage do
    Mix.shell().error("Usage: mix raxol.demo [NAME]")
    Mix.shell().error("")
    Mix.shell().error("Run without arguments for interactive picker.")
    Mix.shell().error("Run with --list to see available demos.")
  end
end
