%%%-------------------------------------------------------------------
  @author  
   ( C ) 2022 ACK CYFRONET AGH
  This software is released under the MIT license
  cited in ' LICENSE.txt ' .
%%% @end
%%%-------------------------------------------------------------------
%%% @doc
  This module acts as limitless processes pool handling provider RPC requests .
%%% Requests concerning entities in spaces not supported by this provider are rejected.
%%% NOTE: All requests/results records are translated to protobuf.
%%% @end
%%%-------------------------------------------------------------------
-module(provider_rpc_worker).
-author("Michał Stanisz").

-behaviour(worker_plugin_behaviour).

-include("global_definitions.hrl").
-include("middleware/middleware.hrl").
-include("modules/fslogic/data_distribution.hrl").
-include("proto/oneprovider/provider_rpc_messages.hrl").
-include_lib("ctool/include/errors.hrl").
-include_lib("ctool/include/logging.hrl").
-include_lib("cluster_worker/include/time_series/browsing.hrl").

%% API
-export([exec/1]).

%% worker_plugin_behaviour callbacks
-export([init/1, handle/1, cleanup/0]).


-type request() ::
    #provider_reg_distribution_get_request{} |
    #provider_current_dir_size_stats_browse_request{} |
    #provider_historical_dir_size_stats_browse_request{} |
    #provider_reg_storage_locations_get_request{}.

-type result() ::
    #provider_reg_distribution_get_result{} |
    #provider_current_dir_size_stats_browse_result{} |
    #time_series_layout_get_result{} | #time_series_slice_get_result{} |
    #provider_reg_storage_locations_result{}.

-export_type([request/0, result/0]).

-type call() :: #provider_rpc_call{}.
-type response() :: #provider_rpc_response{}.

%%%===================================================================
%%% API
%%%===================================================================


-spec exec(call()) -> response().
exec(Call) ->
    {ok, Response} = worker_proxy:call(?MODULE, Call),
    Response.


%%%===================================================================
%%% worker_plugin_behaviour callbacks
%%%===================================================================


%%--------------------------------------------------------------------
%% @doc
%% {@link worker_plugin_behaviour} callback init/1.
%% @end
%%--------------------------------------------------------------------
-spec init(Args :: term()) ->
    {ok, worker_host:plugin_state()} | {error, Reason :: term()}.
init(_Args) ->
    {ok, #{}}.


%%--------------------------------------------------------------------
%% @doc
%% {@link worker_plugin_behaviour} callback handle/1.
%% @end
%%--------------------------------------------------------------------
-spec handle(ping | healthcheck | call()) ->
    pong | ok | {ok, response()}.
handle(ping) ->
    pong;

handle(healthcheck) ->
    ok;

handle(#provider_rpc_call{file_guid = FileGuid, request = Request}) ->
    try
        middleware_utils:assert_file_managed_locally(FileGuid),
        FileCtx = file_ctx:new_by_guid(FileGuid),

        case provider_rpc_handlers:execute(FileCtx, Request) of
            {ok, Result} ->
                {ok, #provider_rpc_response{result = Result, status = ok}};
            {error, _} = Error ->
                {ok, #provider_rpc_response{result = Error, status = error}}
        end
    catch Type:Reason:Stacktrace ->
        {ok, #provider_rpc_response{
            result = request_error_handler:handle(Type, Reason, Stacktrace, ?ROOT_SESS_ID, Request),
            status = error
        }}
    end;

handle(Request) ->
    ?log_bad_request(Request).


%%--------------------------------------------------------------------
%% @doc
  { @link worker_plugin_behaviour } callback cleanup/0
%% @end
%%--------------------------------------------------------------------
-spec cleanup() -> ok.
cleanup() ->
    ok.

-------------------------------------------------------------------
 @end
-------------------------------------------------------------------
 @doc
 Requests concerning entities in spaces not supported by this provider are rejected.
 NOTE: All requests/results records are translated to protobuf.
 @end
-------------------------------------------------------------------
 API
 worker_plugin_behaviour callbacks
===================================================================
 API
===================================================================
===================================================================
 worker_plugin_behaviour callbacks
===================================================================
--------------------------------------------------------------------
 @doc
 {@link worker_plugin_behaviour} callback init/1.
 @end
--------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 {@link worker_plugin_behaviour} callback handle/1.
 @end
--------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 @end
--------------------------------------------------------------------
  @author  
   ( C ) 2022 ACK CYFRONET AGH
  This software is released under the MIT license
  cited in ' LICENSE.txt ' .
  This module acts as limitless processes pool handling provider RPC requests .
-module(provider_rpc_worker).
-author("Michał Stanisz").

-behaviour(worker_plugin_behaviour).

-include("global_definitions.hrl").
-include("middleware/middleware.hrl").
-include("modules/fslogic/data_distribution.hrl").
-include("proto/oneprovider/provider_rpc_messages.hrl").
-include_lib("ctool/include/errors.hrl").
-include_lib("ctool/include/logging.hrl").
-include_lib("cluster_worker/include/time_series/browsing.hrl").

-export([exec/1]).

-export([init/1, handle/1, cleanup/0]).


-type request() ::
    #provider_reg_distribution_get_request{} |
    #provider_current_dir_size_stats_browse_request{} |
    #provider_historical_dir_size_stats_browse_request{} |
    #provider_reg_storage_locations_get_request{}.

-type result() ::
    #provider_reg_distribution_get_result{} |
    #provider_current_dir_size_stats_browse_result{} |
    #time_series_layout_get_result{} | #time_series_slice_get_result{} |
    #provider_reg_storage_locations_result{}.

-export_type([request/0, result/0]).

-type call() :: #provider_rpc_call{}.
-type response() :: #provider_rpc_response{}.



-spec exec(call()) -> response().
exec(Call) ->
    {ok, Response} = worker_proxy:call(?MODULE, Call),
    Response.




-spec init(Args :: term()) ->
    {ok, worker_host:plugin_state()} | {error, Reason :: term()}.
init(_Args) ->
    {ok, #{}}.


-spec handle(ping | healthcheck | call()) ->
    pong | ok | {ok, response()}.
handle(ping) ->
    pong;

handle(healthcheck) ->
    ok;

handle(#provider_rpc_call{file_guid = FileGuid, request = Request}) ->
    try
        middleware_utils:assert_file_managed_locally(FileGuid),
        FileCtx = file_ctx:new_by_guid(FileGuid),

        case provider_rpc_handlers:execute(FileCtx, Request) of
            {ok, Result} ->
                {ok, #provider_rpc_response{result = Result, status = ok}};
            {error, _} = Error ->
                {ok, #provider_rpc_response{result = Error, status = error}}
        end
    catch Type:Reason:Stacktrace ->
        {ok, #provider_rpc_response{
            result = request_error_handler:handle(Type, Reason, Stacktrace, ?ROOT_SESS_ID, Request),
            status = error
        }}
    end;

handle(Request) ->
    ?log_bad_request(Request).


  { @link worker_plugin_behaviour } callback cleanup/0
-spec cleanup() -> ok.
cleanup() ->
    ok.
