src/safe_cmd_fingerprint.erl

-module(safe_cmd_fingerprint).

%% Handles the 'fingerprint' task.
%%
%% Config resolution for fingerprint:
%%   - If .safe/config.json exists, use it directly.
%%   - Otherwise, generate config, show it to the user, and ask for confirmation.
%%     If the user confirms, run fingerprint with the inline JSON.
%%     If the user rejects, save the config to disk and abort so they can edit it.

-export([handle/3]).

-spec handle(safe_rebar_interface:state(), string(), boolean()) ->
    {ok, safe_rebar_interface:state()} | {error, string()}.
handle(State, Dir, Debug) ->
    case safe_cmd_download:ensure_binary_available(Dir, Debug) of
        ok -> fingerprint_with_config(State, Dir, Debug);
        {error, Reason} -> task_error(Reason)
    end.

%%====================================================================
%% Internal functions
%%====================================================================

fingerprint_with_config(State, Dir, Debug) ->
    case resolve_config(State, Dir, Debug) of
        {ok, ConfigSpec} ->
            run_fingerprint(State, Dir, ConfigSpec);
        {aborted, Msg} ->
            safe_print:status(Msg),
            {ok, State};
        {error, Reason} ->
            task_error(Reason)
    end.

run_fingerprint(State, Dir, ConfigSpec) ->
    safe_print:status("* running SAFE fingerprint"),
    case safe_runner:fingerprint(Dir, ConfigSpec) of
        ok ->
            safe_print:status("* SAFE fingerprint complete"),
            {ok, State};
        {error, {fingerprint, ExitCode}} ->
            safe_print:error("SAFE fingerprint failed."),
            {error, safe_errors:format_error({fingerprint_failed, ExitCode})}
    end.

resolve_config(State, Dir, Debug) ->
    ConfigFile = safe_cmd_util:config_file_path(Dir),
    case filelib:is_file(ConfigFile) of
        true -> safe_cmd_util:use_existing_config(ConfigFile, Debug);
        false -> generate_and_confirm_config(State, Dir, Debug)
    end.

generate_and_confirm_config(State, Dir, Debug) ->
    case safe_cmd_util:get_config(State, Debug) of
        {ok, ConfigMap} -> confirm_config(ConfigMap, Dir);
        {error, _} = Err -> Err
    end.

confirm_config(ConfigMap, Dir) ->
    Encoded = jsx:encode(ConfigMap, [{space, 1}, {indent, 2}]),
    io:format("~s~n", [Encoded]),
    case safe_io:bool_prompt("Would you like to proceed with this configuration?") of
        true ->
            Compact = lists:flatten(io_lib:format("~s", [jsx:encode(ConfigMap)])),
            {ok, {config_json, Compact}};
        false ->
            save_and_abort(ConfigMap, Dir)
    end.

save_and_abort(ConfigMap, Dir) ->
    ConfigFile = safe_cmd_util:config_file_path(Dir),
    case safe_config:save(ConfigFile, ConfigMap) of
        ok ->
            {aborted,
                "Config saved to .safe/config.json. "
                "Edit it as needed, then re-run 'rebar3 safe fingerprint'.\n"
                "See https://safe-docs.erlang-solutions.com/ for configuration reference."};
        {error, _} = Err ->
            Err
    end.

task_error(Reason) ->
    safe_print:error(io_lib:format("~s", [safe_errors:format_error(Reason)])),
    {error, safe_errors:format_error(Reason)}.