import type { ChatInputCommandInteraction } from "discord.js";
import { UserError } from "@shared/lib/errors";
import { createErrorEmbed } from "./embeds";

/**
 * Wraps a command's core logic with standardized error handling.
 *
 * - Calls `interaction.deferReply()` automatically
 * - On success, invokes `onSuccess` callback or sends `successMessage`
 * - On `UserError`, shows the error message in an error embed
 * - On unexpected errors, logs to console and shows a generic error embed
 *
 * @example
 * ```typescript
 * export const myCommand = createCommand({
 *   execute: async (interaction) => {
 *     await withCommandErrorHandling(
 *       interaction,
 *       async () => {
 *         const result = await doSomething();
 *         await interaction.editReply({ embeds: [createSuccessEmbed(result)] });
 *       }
 *     );
 *   }
 * });
 * ```
 *
 * @example
 * ```typescript
 * // With deferReply options (e.g. ephemeral)
 * await withCommandErrorHandling(
 *   interaction,
 *   async () => doSomething(),
 *   {
 *     ephemeral: true,
 *     successMessage: "Done!",
 *   }
 * );
 * ```
 */
export async function withCommandErrorHandling<T>(
    interaction: ChatInputCommandInteraction,
    operation: () => Promise<T>,
    options?: {
        /** Message to send on success (if no onSuccess callback is provided) */
        successMessage?: string;
        /** Callback invoked with the operation result on success */
        onSuccess?: (result: T) => Promise<void>;
        /** Whether the deferred reply should be ephemeral */
        ephemeral?: boolean;
    }
): Promise<T | undefined> {
    try {
        await interaction.deferReply({ ephemeral: options?.ephemeral });
        const result = await operation();

        if (options?.onSuccess) {
            await options.onSuccess(result);
        } else if (options?.successMessage) {
            await interaction.editReply({
                content: options.successMessage,
            });
        }

        return result;
    } catch (error) {
        if (error instanceof UserError) {
            await interaction.editReply({
                embeds: [createErrorEmbed(error.message)],
            });
        } else {
            console.error("Unexpected error in command:", error);
            await interaction.editReply({
                embeds: [createErrorEmbed("An unexpected error occurred.")],
            });
        }
        return undefined;
    }
}
