%%%-------------------------------------------------------------------
%%% @author licheng5
%%% @copyright (C) 2020, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 26. 4月 2020 3:36 下午
%%%-------------------------------------------------------------------
-module(endpoint_handler).
-author("licheng5").
-include_lib("endpoint/include/endpoint.hrl").

%% API
-export([handle_request/4]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% helper methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% 获取endpoint的运行状态
handle_request("POST", "/endpoint/run_statuses", _, Ids) when is_list(Ids) ->
    Statuses = lists:map(fun(Id) ->
        case endpoint:get_pid(Id) of
            undefined ->
                0;
            Pid when is_pid(Pid) ->
                1
        end
                         end, Ids),
    {ok, 200, iot_util:json_data(Statuses)};

handle_request("POST", "/endpoint/start", _, #{<<"id">> := Id}) when is_integer(Id) ->
    case iot_api_client:get_endpoint(Id) of
        undefined ->
            {ok, 200, iot_util:json_error(404, <<"endpoint not found">>)};
        {ok, EndpointInfo} ->
            case endpoint:endpoint_record(EndpointInfo) of
                {ok, Endpoint = #endpoint{title = Title}} ->
                    case endpoint_adapter_sup:ensured_endpoint_started(Endpoint) of
                        {ok, Pid} when is_pid(Pid) ->
                            {ok, 200, iot_util:json_data(<<"success">>)};
                        {error, Reason} ->
                            logger:warning("[endpoint_handler] start endpoint: ~p, get error: ~p", [Title, Reason]),
                            {ok, 200, iot_util:json_error(404, <<"start endpoint error">>)}
                    end;
                error ->
                    {ok, 200, iot_util:json_error(404, <<"endpoint invalid">>)}
            end
    end;

handle_request("POST", "/endpoint/stop", _, #{<<"id">> := Id}) when is_integer(Id) ->
    case iot_api_client:get_endpoint(Id) of
        undefined ->
            {ok, 200, iot_util:json_error(404, <<"endpoint not found">>)};
        {ok, _} ->
            case endpoint_adapter_sup:delete_endpoint(Id) of
                ok ->
                    {ok, 200, iot_util:json_data(<<"success">>)};
                {error, Reason} ->
                    logger:warning("[endpoint_handler] stop endpoint id: ~p, get error: ~p", [Id, Reason]),
                    {ok, 200, iot_util:json_error(404, <<"stop endpoint error">>)}
            end
    end;

handle_request("POST", "/endpoint/restart", _, #{<<"id">> := Id}) when is_integer(Id) ->
    case iot_api_client:get_endpoint(Id) of
        undefined ->
            {ok, 200, iot_util:json_error(404, <<"endpoint not found">>)};
        {ok, EndpointInfo} ->
            case endpoint:endpoint_record(EndpointInfo) of
                {ok, Endpoint = #endpoint{title = Title}} ->
                    case endpoint:get_pid(Id) of
                        undefined ->
                            case endpoint_adapter_sup:ensured_endpoint_started(Endpoint) of
                                {ok, Pid} when is_pid(Pid) ->
                                    {ok, 200, iot_util:json_data(<<"success">>)};
                                {error, Reason} ->
                                    logger:warning("[endpoint_handler] start endpoint: ~p, get error: ~p", [Title, Reason]),
                                    {ok, 200, iot_util:json_error(404, <<"restart endpoint error">>)}
                            end;
                        Pid when is_pid(Pid) ->
                            case endpoint_adapter_sup:delete_endpoint(Id) of
                                ok ->
                                    case endpoint_adapter_sup:ensured_endpoint_started(Endpoint) of
                                        {ok, Pid0} when is_pid(Pid0) ->
                                            {ok, 200, iot_util:json_data(<<"success">>)};
                                        {error, Reason} ->
                                            logger:warning("[endpoint_handler] start endpoint: ~p, get error: ~p", [Title, Reason]),
                                            {ok, 200, iot_util:json_error(404, <<"restart endpoint error">>)}
                                    end;
                                {error, Reason} ->
                                    logger:warning("[endpoint_handler] start endpoint: ~p, get error: ~p", [Title, Reason]),
                                    {ok, 200, iot_util:json_error(404, <<"stop endpoint error">>)}
                            end
                    end;
                error ->
                    {ok, 200, iot_util:json_error(404, <<"endpoint invalid">>)}
            end
    end;

%% http接口的测试
handle_request("POST", "/endpoint/test", _, #{<<"protocol">> := <<"http">>, <<"config">> := #{<<"url">> := Url, <<"pool_size">> := PoolSize}}) when is_integer(PoolSize), PoolSize > 0 ->
    case endpoint_tester:test(#http_endpoint{url = Url, pool_size = PoolSize}) of
        ok ->
            {ok, 200, iot_util:json_data(<<"ok">>)};
        {error, Reason} ->
            logger:debug("[endpint_handler] test http: ~p, error: ~p", [Url, Reason]),
            {ok, 200, iot_util:json_error(-1, <<"url failed">>)}
    end;

%% 测试mqtt
handle_request("POST", "/endpoint/test", _, #{<<"protocol">> := <<"mqtt">>, <<"config">> := Config}) ->
    case endpoint:parse_config(<<"mqtt">>, Config) of
        {ok, MqttEndpoint = #mqtt_endpoint{}} ->
            case endpoint_tester:test(MqttEndpoint) of
                ok ->
                    {ok, 200, iot_util:json_data(<<"ok">>)};
                {error, Reason} ->
                    {ok, 200, iot_util:json_error(-1, Reason)}
            end;
        {error, Errors} ->
            {ok, 200, iot_util:json_error(-1, Errors)}
    end;

%% 测试kafka
handle_request("POST", "/endpoint/test", _, #{<<"protocol">> := <<"kafka">>, <<"config">> := Config}) ->
    case endpoint:parse_config(<<"kafka">>, Config) of
        {ok, KafkaEndpoint = #kafka_endpoint{}} ->
            case endpoint_tester:test(KafkaEndpoint) of
                ok ->
                    {ok, 200, iot_util:json_data(<<"ok">>)};
                {error, Reason} ->
                    {ok, 200, iot_util:json_error(-1, Reason)}
            end;
        {error, Errors} ->
            {ok, 200, iot_util:json_error(-1, Errors)}
    end;

%% 发布消息
handle_request("POST", "/endpoint/publish_metric", _, #{<<"route_key">> := RouteKey, <<"metric">> := Metric0}) when is_binary(RouteKey) ->
    if
        is_map(Metric0) orelse is_list(Metric0) ->
            Metric = iolist_to_binary(json:encode(Metric0)),
            endpoint_subscription:publish(RouteKey, Metric),
            {ok, 200, iot_util:json_data(<<"ok">>)};
        is_binary(Metric0) ->
            endpoint_subscription:publish(RouteKey, Metric0),
            {ok, 200, iot_util:json_data(<<"ok">>)};
        true ->
            {ok, 200, iot_util:json_error(-1, <<"invalid metric">>)}
    end;

handle_request(_, Path, _, _) ->
    Path1 = list_to_binary(Path),
    {ok, 200, iot_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}.
