lib/mix/tasks/llm_core.config.validate.ex

defmodule Mix.Tasks.LlmCore.Config.Validate do
  @moduledoc """
  Validates `llm_core.toml` configuration and prints provider availability.

  Loads the merged TOML configuration, normalizes provider definitions, and
  displays each provider's availability status and alias mappings. Also shows
  the current routing table if one was loaded.

  ## Examples

      mix llm_core.config.validate
      mix llm_core.config.validate --path /custom/llm_core.toml
  """
  use Mix.Task

  @shortdoc "Validates llm_core TOML configuration"

  @impl true
  @spec run([String.t()]) :: :ok
  def run(args) do
    Mix.Task.run("app.start")

    {opts, _, _} = OptionParser.parse(args, switches: [path: :string])

    case LlmCore.Config.Loader.reload_providers(opts) do
      {:ok, providers} ->
        print_summary(providers)

      {:error, reason} ->
        Mix.raise("Failed to load configuration: #{inspect(reason)}")
    end
  end

  defp print_summary(providers) do
    IO.puts("Loaded #{map_size(providers)} providers:\n")

    providers
    |> Enum.sort_by(fn {id, _} -> id end)
    |> Enum.each(fn {id, definition} ->
      status = if definition.available?, do: "available", else: "unavailable"
      aliases = Enum.join(definition.aliases, ", ")

      kind_label =
        if definition.provider_kind == :cli, do: "CLI", else: inspect(definition.module)

      IO.puts("- #{id} (#{kind_label}) -> #{status} [aliases: #{aliases}]")
    end)

    case LlmCore.Config.Store.get_routing() do
      {:ok, table} ->
        IO.puts("\nRouting default: #{table.default.alias}")

        Enum.each(table.rules, fn {task, entry} ->
          IO.puts("  #{task} => #{entry.alias} (#{entry.mode})")
        end)

      _ ->
        IO.puts("\nNo routing table loaded")
    end
  end
end