%%%-------------------------------------------------------------------
%%% @author aresei
%%% @copyright (C) 2023, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 30. 5月 2023 11:28
%%%-------------------------------------------------------------------
-module(influx_point).
-author("aresei").

-record(point, {
    measurement,
    tags = [],
    fields = [],
    time = 0 :: integer()
}).

%% API
-export([new/4, normalized/1]).

-spec new(Measurement :: binary(), Tags :: list() | map(), Fields :: list() | map(), Timestamp :: integer()) -> #point{}.
new(Measurement, Tags, Fields, Timestamp) when is_binary(Measurement), is_list(Tags); is_map(Tags), is_list(Fields); is_map(Fields), is_integer(Timestamp) ->
    #point{measurement = Measurement, tags = as_list(Tags), fields = as_list(Fields), time = Timestamp}.

normalized(#point{measurement = Name, tags = Tags, fields = Fields, time = Time}) ->
    NTags = lists:map(fun({N, V}) -> <<N/binary, $=, V/binary>> end, Tags),
    NFields = lists:map(fun({K, V}) -> <<K/binary, $=, (field_val(V))/binary>> end, Fields),

    TagItems = lists:join(<<",">>, [Name | NTags]),
    FieldItems = lists:join(<<",">>, NFields),

    NTime = case Time > 0 of
                true  -> Time;
                false -> iot_util:timestamp()
            end,

    erlang:iolist_to_binary([TagItems, <<" ">>, FieldItems, <<" ">>, integer_to_binary(NTime)]).

field_val(V) when is_integer(V) ->
    integer_to_binary(V);
field_val(V) when is_float(V) ->
    %% 默认按照浮点数表示
    iot_util:float_to_binary(V, 6);
field_val(V) when is_binary(V) ->
    <<$", V/binary, $">>;
field_val(V) when is_list(V); is_map(V) ->
    S = base64:encode(iolist_to_binary(json:encode(V))),
    <<$", "base64:", S/binary, $">>;
field_val(true) ->
    <<"true">>;
field_val(false) ->
    <<"false">>.

as_list(L) when is_list(L) ->
    L;
as_list(L) when is_map(L) ->
    maps:to_list(L).
