%%%-------------------------------------------------------------------
%% @doc endpoint top level supervisor.
%% @end
%%%-------------------------------------------------------------------

-module(endpoint_adapter_sup).

-behaviour(supervisor).
-include("endpoint.hrl").

-export([start_link/0]).
-export([ensured_endpoint_started/1, delete_endpoint/1]).
-export([start_endpoints/1]).

-export([init/1]).

-define(SERVER, ?MODULE).

start_link() ->
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

%% sup_flags() = #{strategy => strategy(),         % optional
%%                 intensity => non_neg_integer(), % optional
%%                 period => pos_integer()}        % optional
%% child_spec() = #{id => child_id(),       % mandatory
%%                  start => mfargs(),      % mandatory
%%                  restart => restart(),   % optional
%%                  shutdown => shutdown(), % optional
%%                  type => worker(),       % optional
%%                  modules => modules()}   % optional
init([]) ->
    SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600},
    {ok, {SupFlags, []}}.

-spec start_endpoints(Endpoints :: list()) -> ok.
start_endpoints(Endpoints) when is_list(Endpoints) ->
    lists:foreach(fun(Endpoint) ->
        Spec = child_spec(Endpoint),
        {ok, _} = supervisor:start_child(?MODULE, Spec)
                  end, Endpoints),
    ok.

-spec ensured_endpoint_started(Endpoint :: #endpoint{}) -> {ok, Pid :: pid()} | {error, Reason :: any()}.
ensured_endpoint_started(Endpoint = #endpoint{}) ->
    case supervisor:start_child(?MODULE, child_spec(Endpoint)) of
        {ok, Pid} when is_pid(Pid) ->
            {ok, Pid};
        {error, {'already_started', Pid}} when is_pid(Pid) ->
            {ok, Pid};
        {error, Error} ->
            {error, Error}
    end.

-spec delete_endpoint(Id :: integer()) -> ok | {error, Reason :: any()}.
delete_endpoint(Id) when is_integer(Id) ->
    Name = endpoint:get_name(Id),
    case supervisor:terminate_child(?MODULE, Name) of
        ok ->
            delete_endpoint_child(Name);
        {error, not_found} ->
            delete_endpoint_child(Name);
        {error, Reason} ->
            {error, Reason}
    end.

delete_endpoint_child(Name) ->
    case supervisor:delete_child(?MODULE, Name) of
        ok ->
            ok;
        {error, not_found} ->
            ok;
        {error, Reason} ->
            {error, Reason}
    end.

child_spec(Endpoint = #endpoint{id = Id}) ->
    Name = endpoint:get_name(Id),
    #{id => Name,
        start => {endpoint, start_link, [Endpoint]},
        restart => permanent,
        shutdown => 2000,
        type => worker,
        modules => ['endpoint']}.
