# SPDX-FileCopyrightText: 2020 Frank Hunleth
# SPDX-FileCopyrightText: 2022 Jon Carstens
#
# SPDX-License-Identifier: Apache-2.0
#
defmodule VintageNet.PowerManager.Supervisor do
  @moduledoc """
  Supervision for all of the power management controllers
  """
  use Supervisor
  require Logger

  @spec start_link(any()) :: Supervisor.on_start()
  def start_link(args) do
    Supervisor.start_link(__MODULE__, args, name: __MODULE__)
  end

  @impl Supervisor
  def init(_) do
    power_manager_specs =
      Application.get_env(:vintage_net, :power_managers)
      |> Enum.flat_map(&power_manager_to_spec/1)

    children =
      [
        {Registry, keys: :unique, name: VintageNet.PowerManager.Registry}
      ] ++ power_manager_specs

    Supervisor.init(children, strategy: :one_for_one)
  end

  defp power_manager_to_spec({module, args}) when is_atom(module) and is_list(args) do
    with {:ok, ifname} <- fetch_ifname(args),
         :ok <- check_module(module) do
      id = Module.concat(VintageNet.PowerManager.PMControl, ifname)

      [
        Supervisor.child_spec(
          {VintageNet.PowerManager.PMControl, impl: module, impl_args: args},
          id: id
        )
      ]
    else
      {:error, reason} ->
        Logger.warning("Ignoring power management spec for #{module} since #{reason}")
        []
    end
  end

  defp power_manager_to_spec(other) do
    Logger.warning("Ignoring invalid power manager spec #{inspect(other)}")
    []
  end

  defp fetch_ifname(args) do
    case Keyword.fetch(args, :ifname) do
      {:ok, ifname} -> {:ok, ifname}
      :error -> {:error, "missing `:ifname` key"}
    end
  end

  defp check_module(module) do
    case Code.ensure_loaded?(module) do
      true -> :ok
      false -> {:error, "invalid module"}
    end
  end
end
