-module(cake@internal@prepared_statement).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).

-export([new/2, append_sql/2, get_prefix/1, get_sql/1, get_params/1, get_dialect/1, append_param/2]).
-export_type([prepared_statement/0]).

-opaque prepared_statement() :: {prepared_statement,
        binary(),
        binary(),
        list(cake@param:param()),
        integer(),
        cake@internal@dialect:dialect()}.

-spec new(binary(), cake@internal@dialect:dialect()) -> prepared_statement().
new(Plchldr_bs, Db_adptr) ->
    _pipe = Plchldr_bs,
    {prepared_statement, _pipe, <<""/utf8>>, [], 0, Db_adptr}.

-spec append_sql(prepared_statement(), binary()) -> prepared_statement().
append_sql(Prp_stm, Nw_sql) ->
    erlang:setelement(
        3,
        Prp_stm,
        <<(erlang:element(3, Prp_stm))/binary, Nw_sql/binary>>
    ).

-spec get_prefix(prepared_statement()) -> binary().
get_prefix(Prp_stm) ->
    erlang:element(2, Prp_stm).

-spec get_sql(prepared_statement()) -> binary().
get_sql(Prp_stm) ->
    erlang:element(3, Prp_stm).

-spec get_params(prepared_statement()) -> list(cake@param:param()).
get_params(Prp_stm) ->
    erlang:element(4, Prp_stm).

-spec get_dialect(prepared_statement()) -> cake@internal@dialect:dialect().
get_dialect(Prp_stm) ->
    erlang:element(6, Prp_stm).

-spec append_sql_and_params(
    prepared_statement(),
    binary(),
    list(cake@param:param())
) -> prepared_statement().
append_sql_and_params(Prp_stm, Nw_sql, Nw_prms) ->
    erlang:setelement(
        5,
        erlang:setelement(
            4,
            erlang:setelement(
                3,
                Prp_stm,
                <<(erlang:element(3, Prp_stm))/binary, Nw_sql/binary>>
            ),
            begin
                _pipe = erlang:element(4, Prp_stm),
                lists:append(_pipe, Nw_prms)
            end
        ),
        erlang:element(5, Prp_stm) + erlang:length(Nw_prms)
    ).

-spec append_sql_and_param(prepared_statement(), binary(), cake@param:param()) -> prepared_statement().
append_sql_and_param(Prp_stm, Nw_sql, Nw_prm) ->
    _pipe = Prp_stm,
    append_sql_and_params(_pipe, Nw_sql, [Nw_prm]).

-spec next_placeholder(prepared_statement(), cake@internal@dialect:dialect()) -> binary().
next_placeholder(Prp_stm, Dlct) ->
    case Dlct of
        postgres ->
            <<(erlang:element(2, Prp_stm))/binary,
                (begin
                    _pipe = erlang:element(5, Prp_stm),
                    _pipe@1 = gleam@int:add(_pipe, 1),
                    gleam@int:to_string(_pipe@1)
                end)/binary>>;

        sqlite ->
            <<(erlang:element(2, Prp_stm))/binary,
                (begin
                    _pipe = erlang:element(5, Prp_stm),
                    _pipe@1 = gleam@int:add(_pipe, 1),
                    gleam@int:to_string(_pipe@1)
                end)/binary>>;

        maria ->
            erlang:element(2, Prp_stm);

        mysql ->
            erlang:element(2, Prp_stm)
    end.

-spec append_param(prepared_statement(), cake@param:param()) -> prepared_statement().
append_param(Prp_stm, Nw_prm) ->
    New_sql = begin
        _pipe = Prp_stm,
        next_placeholder(_pipe, erlang:element(6, Prp_stm))
    end,
    _pipe@1 = Prp_stm,
    append_sql_and_param(_pipe@1, New_sql, Nw_prm).
