-module(store_handler).
-behavior(cowboy_rest).

-export([init/2]).
-export([allowed_methods/2]).
-export([content_types_accepted/2]).
-export([content_types_provided/2]).
-export([resource_exists/2]).
-export([delete_resource/2]).
-export([from_json/2]).
-export([to_json/2]).

init(Req, State) ->
  {cowboy_rest, Req, State}.

allowed_methods(Req, State) ->
  {[
    <<"GET">>,
    <<"HEAD">>,
    <<"PUT">>,
    <<"DELETE">>,
    <<"OPTIONS">>
  ], Req, State}.

content_types_accepted(Req, State) ->
  {[
    {<<"application/json">>, from_json}
  ],
  Req, State}.

content_types_provided(Req, State) ->
  {[
    {<<"application/json">>, to_json}
  ], Req, State}.

resource_exists(Req, State) ->
  case cowboy_req:binding(item_id, Req) of
    undefined ->
      %% Collections always exist.
      {true, Req, State};
    ItemID ->
      case get_item(ItemID) of
        not_found ->
          {false, Req, State#{item_id => ItemID}};
        Item ->
          {true, Req, State#{item_id => ItemID, item => Item}}
      end
  end.

delete_resource(Req, #{item_id := ItemID, item := Item} = State) ->
  ets:delete(table(), ItemID),
  Req1 = cowboy_req:set_resp_body(Item, Req),
  {true, Req1, State}.

from_json(Req, #{item_id := ItemID} = State) ->
  {ok, Body, Req1} = cowboy_req:read_body(Req),
  {ok, Item} = thoas:decode(Body),
  set_item(ItemID, Item),
  {true, Req1, State}.

to_json(Req, #{item := Item} = State) ->
  {thoas:encode(Item), Req, State};

to_json(Req, State) ->
  Collection = get_collection(),
  {thoas:encode(Collection), Req, State}.

%%
%% Internal.
%%
table() -> workloads_store.

set_item(ItemID, Item) ->
  ets:insert(table(), {ItemID, Item}).

get_item(ItemID) ->
  ets:lookup_element(table(), ItemID, 2, not_found).

get_collection() ->
  [ Item || {_ItemID, Item} <- ets:tab2list(table()) ].