% Copyright (c) 2025 Onomondo ApS & sysmocom - s.f.m.c. GmbH. All rights reserved.
%
% SPDX-License-Identifier: AGPL-3.0-only
%
% Author: Harald Welte <hwelte@sysmocom.de> / sysmocom - s.f.m.c. GmbH

-module(rest_middleware).
-behaviour(cowboy_middleware).

-export([execute/2]).

% Derive the X-ADMIN-PROTOCOL string from the URN contained in the $id field of the related JSON schema.
protocol_from_json_schema(JsonSchemaName) ->
    JsonSchema = jesse_database:load(JsonSchemaName),
    {[{<<"$id">>, JsonSchemaId} | _]} = JsonSchema,
    JsonSchemaIdUrnPath = maps:get(path, uri_string:parse(JsonSchemaId)),
    [_, Protocol] = string:split(JsonSchemaIdUrnPath, ":"),
    Protocol.

% Cowboy middleware callback, make sure that the X-ADMIN-PROTOCOL field contains the expected protocol
% identifier for incoming POST requests. For outgoing requests, set the X-ADMIN-PROTOCOL. Both strings
% are derived from the related JSON schema.
execute(Req0 = #{method := <<"POST">>}, State) ->
    ExpectedProtocol = protocol_from_json_schema("rest_api_resource_schema"),
    case cowboy_req:header(<<"x-admin-protocol">>, Req0) of
        ExpectedProtocol ->
            {ok, Req0, State};
        Protocol ->
            logger:error(
                "Rejecting incompatible REST request: ~s,~nProtocol=~p, Peer=~p, Pid=~p~n",
                [maps:get(path, Req0), Protocol, maps:get(peer, Req0), maps:get(pid, Req0)]
            ),
            Req = cowboy_req:reply(400, #{}, <<"Unsupported x-admin-protocol">>, Req0),
            {stop, Req}
    end;
execute(Req0, Env) ->
    Protocol = protocol_from_json_schema("rest_api_response_schema"),
    Req1 = cowboy_req:set_resp_header(<<"x-admin-protocol">>, Protocol, Req0),
    {ok, Req1, Env}.
