-module(db@session_key).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).

-export([add/3, validate/3]).
-export_type([add_err/0, get_err/0]).

-type add_err() :: {add_db_err, binary()}.

-type get_err() :: invalid_user | invalid_session_key | {get_db_err, binary()}.

-spec insert(sqlight:connection(), integer(), binary()) -> {ok, nil} |
    {error, sqlight:error()}.
insert(Conn, User_id, Session_key) ->
    Row = [cake@insert:string(Session_key), cake@insert:int(User_id)],
    Fields = [<<"key"/utf8>>, <<"user_id"/utf8>>],
    Query = begin
        _pipe@1 = cake@insert:from_values(
            <<"sessionKeys"/utf8>>,
            Fields,
            [begin
                    _pipe = Row,
                    cake@insert:row(_pipe)
                end]
        ),
        cake@insert:to_query(_pipe@1)
    end,
    Decoder = gleam@dynamic:decode2(
        fun(Key, User_id@1) -> {Key, User_id@1} end,
        gleam@dynamic:field(<<"key"/utf8>>, fun gleam@dynamic:string/1),
        gleam@dynamic:field(<<"user_id"/utf8>>, fun gleam@dynamic:string/1)
    ),
    _pipe@2 = Conn,
    db@db:insert(_pipe@2, Query, Decoder).

-spec add(sqlight:connection(), integer(), binary()) -> {ok, nil} |
    {error, add_err()}.
add(Conn, User_id, Sesion_key) ->
    _pipe = Conn,
    _pipe@2 = insert(
        _pipe,
        User_id,
        begin
            _pipe@1 = Sesion_key,
            users@user:hash(_pipe@1)
        end
    ),
    gleam@result:map_error(
        _pipe@2,
        fun(E) -> {add_db_err, erlang:element(3, E)} end
    ).

-spec select(sqlight:connection(), binary()) -> {ok,
        list({integer(), binary()})} |
    {error, sqlight:error()}.
select(Conn, Username) ->
    U_table = <<"users"/utf8>>,
    Join = cake@join:inner(
        cake@join:table(U_table),
        begin
            _pipe = cake@where:col(<<U_table/binary, ".id"/utf8>>),
            cake@where:eq(
                _pipe,
                cake@where:col(<<"sessionKeys"/utf8, ".user_id"/utf8>>)
            )
        end,
        U_table
    ),
    Fields = [cake@select:col(<<U_table/binary, ".id"/utf8>>),
        cake@select:col(<<"sessionKeys"/utf8, ".key"/utf8>>)],
    Condition = begin
        _pipe@1 = cake@where:col(<<U_table/binary, ".username"/utf8>>),
        cake@where:eq(
            _pipe@1,
            cake@where:string(
                begin
                    _pipe@2 = Username,
                    gleam@io:debug(_pipe@2)
                end
            )
        )
    end,
    Shape = gleam@dynamic:tuple2(
        fun gleam@dynamic:int/1,
        fun gleam@dynamic:string/1
    ),
    Query = begin
        _pipe@3 = cake@select:new(),
        _pipe@4 = cake@select:selects(_pipe@3, Fields),
        _pipe@5 = cake@select:from_table(_pipe@4, <<"sessionKeys"/utf8>>),
        _pipe@6 = cake@select:join(_pipe@5, Join),
        _pipe@7 = cake@select:where(_pipe@6, Condition),
        cake@select:to_query(_pipe@7)
    end,
    _pipe@8 = Conn,
    db@db:select(_pipe@8, Query, Shape).

-spec validate(sqlight:connection(), binary(), binary()) -> {ok, integer()} |
    {error, get_err()}.
validate(Conn, Username, Key) ->
    _pipe = <<"validating session key"/utf8>>,
    gleam@io:debug(_pipe),
    case begin
        _pipe@1 = Conn,
        select(_pipe@1, Username)
    end of
        {ok, []} ->
            _pipe@2 = invalid_user,
            _pipe@3 = {error, _pipe@2},
            gleam@io:debug(_pipe@3);

        {error, E} ->
            _pipe@4 = {get_db_err, erlang:element(3, E)},
            _pipe@5 = {error, _pipe@4},
            gleam@io:debug(_pipe@5);

        {ok, Pairs} ->
            _assert_subject = begin
                _pipe@6 = Pairs,
                gleam@list:first(_pipe@6)
            end,
            {ok, {U_id, _}} = case _assert_subject of
                {ok, {_, _}} -> _assert_subject;
                _assert_fail ->
                    erlang:error(#{gleam_error => let_assert,
                                message => <<"Assertion pattern match failed"/utf8>>,
                                value => _assert_fail,
                                module => <<"db/session_key"/utf8>>,
                                function => <<"validate"/utf8>>,
                                line => 39})
            end,
            Db_keys = begin
                _pipe@7 = Pairs,
                gleam@list:map(_pipe@7, fun gleam@pair:second/1)
            end,
            case begin
                _pipe@8 = Db_keys,
                _pipe@9 = gleam@io:debug(_pipe@8),
                gleam@list:contains(
                    _pipe@9,
                    begin
                        _pipe@10 = Key,
                        _pipe@11 = users@user:hash(_pipe@10),
                        gleam@io:debug(_pipe@11)
                    end
                )
            end of
                true ->
                    {ok, U_id};

                false ->
                    _pipe@12 = invalid_session_key,
                    {error, _pipe@12}
            end
    end.
