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

-export([get/2, add/4]).
-export_type([add_err/0, get_err/0]).

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

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

-spec validate_add({ok, list(any())} | {error, sqlight:error()}) -> {ok, nil} |
    {error, add_err()}.
validate_add(Result) ->
    case Result of
        {ok, []} ->
            {ok, nil};

        {ok, _} ->
            {error, username_taken};

        {error, E} ->
            {error, {add_db_err, erlang:element(3, E)}}
    end.

-spec user_decoder() -> fun((gleam@dynamic:dynamic_()) -> {ok,
        {binary(), binary(), binary()}} |
    {error, list(gleam@dynamic:decode_error())}).
user_decoder() ->
    gleam@dynamic:decode3(
        fun(Username, Password, Icon) -> {Username, Password, Icon} end,
        gleam@dynamic:field(<<"username"/utf8>>, fun gleam@dynamic:string/1),
        gleam@dynamic:field(<<"password"/utf8>>, fun gleam@dynamic:string/1),
        gleam@dynamic:field(<<"icon"/utf8>>, fun gleam@dynamic:string/1)
    ).

-spec select(sqlight:connection(), binary()) -> {ok,
        list({integer(), binary(), binary(), binary()})} |
    {error, sqlight:error()}.
select(Conn, Username) ->
    Condition = begin
        _pipe = cake@where:col(<<"username"/utf8>>),
        cake@where:eq(_pipe, cake@where:string(Username))
    end,
    Fields = [cake@select:col(<<"id"/utf8>>),
        cake@select:col(<<"username"/utf8>>),
        cake@select:col(<<"password"/utf8>>),
        cake@select:col(<<"icon"/utf8>>)],
    Shape = gleam@dynamic:tuple4(
        fun gleam@dynamic:int/1,
        fun gleam@dynamic:string/1,
        fun gleam@dynamic:string/1,
        fun gleam@dynamic:string/1
    ),
    Query = begin
        _pipe@1 = cake@select:new(),
        _pipe@2 = cake@select:selects(_pipe@1, Fields),
        _pipe@3 = cake@select:from_table(_pipe@2, <<"users"/utf8>>),
        _pipe@4 = cake@select:where(_pipe@3, Condition),
        _pipe@5 = cake@select:limit(_pipe@4, 1),
        cake@select:to_query(_pipe@5)
    end,
    _pipe@6 = Conn,
    db@db:select(_pipe@6, Query, Shape).

-spec get(sqlight:connection(), binary()) -> {ok, users@user:user()} |
    {error, get_err()}.
get(Conn, Username) ->
    case begin
        _pipe = Conn,
        select(_pipe, Username)
    end of
        {ok, [{Id, Name, Pw, Icon} | _]} ->
            _pipe@1 = {user, Id, Name, Pw, Icon},
            {ok, _pipe@1};

        {ok, []} ->
            _pipe@2 = invalid_user,
            {error, _pipe@2};

        {error, E} ->
            _pipe@3 = {get_db_err, erlang:element(3, E)},
            {error, _pipe@3}
    end.

-spec insert(sqlight:connection(), binary(), binary(), binary()) -> {ok, nil} |
    {error, sqlight:error()}.
insert(Conn, Username, Password, Icon) ->
    _pipe = {Username, Password, Icon},
    gleam@io:debug(_pipe),
    Row = [cake@insert:string(Username),
        cake@insert:string(Password),
        cake@insert:string(Icon)],
    Fields = [<<"username"/utf8>>, <<"password"/utf8>>, <<"icon"/utf8>>],
    Query = begin
        _pipe@2 = cake@insert:from_values(
            <<"users"/utf8>>,
            Fields,
            [begin
                    _pipe@1 = Row,
                    cake@insert:row(_pipe@1)
                end]
        ),
        cake@insert:to_query(_pipe@2)
    end,
    _pipe@3 = Conn,
    db@db:insert(
        _pipe@3,
        begin
            _pipe@4 = Query,
            gleam@io:debug(_pipe@4)
        end,
        user_decoder()
    ).

-spec add(sqlight:connection(), binary(), binary(), binary()) -> {ok, nil} |
    {error, add_err()}.
add(Conn, Username, Password, Icon) ->
    gleam@result:'try'(
        begin
            _pipe = Conn,
            _pipe@1 = select(_pipe, Username),
            validate_add(_pipe@1)
        end,
        fun(_use0) ->
            nil = _use0,
            _pipe@2 = Conn,
            _pipe@4 = insert(
                _pipe@2,
                Username,
                begin
                    _pipe@3 = Password,
                    users@user:hash(_pipe@3)
                end,
                Icon
            ),
            gleam@result:map_error(
                _pipe@4,
                fun(E) -> _pipe@5 = {add_db_err, erlang:element(3, E)},
                    gleam@io:debug(_pipe@5) end
            )
        end
    ).
