/**
 * EN: Error handling utilities for type-safe error handling
 * VI: Tiện ích xử lý lỗi cho xử lý lỗi type-safe
 */

/**
 * EN: Type guard to check if error is an Error instance
 * VI: Type guard để kiểm tra xem error có phải là Error instance không
 */
export function isError(error: unknown): error is Error {
    return error instanceof Error;
}

/**
 * EN: Type guard to check if error has a message property
 * VI: Type guard để kiểm tra xem error có property message không
 */
export function hasMessage(error: unknown): error is { message: string } {
    return (
        typeof error === 'object' &&
        error !== null &&
        'message' in error &&
        typeof (error as { message: unknown }).message === 'string'
    );
}

/**
 * EN: Type guard to check if error has a code property
 * VI: Type guard để kiểm tra xem error có property code không
 */
export function hasCode(error: unknown): error is { code: string } {
    return (
        typeof error === 'object' &&
        error !== null &&
        'code' in error &&
        typeof (error as { code: unknown }).code === 'string'
    );
}

/**
 * EN: Get error message from unknown error
 * VI: Lấy error message từ unknown error
 */
export function getErrorMessage(error: unknown): string {
    if (isError(error)) {
        return error.message;
    }

    if (hasMessage(error)) {
        return error.message;
    }

    if (typeof error === 'string') {
        return error;
    }

    return 'Unknown error occurred';
}

/**
 * EN: Get error code from unknown error
 * VI: Lấy error code từ unknown error
 */
export function getErrorCode(error: unknown): string | undefined {
    if (hasCode(error)) {
        return error.code;
    }

    return undefined;
}

/**
 * EN: Format error for logging
 * VI: Format error để logging
 */
export function formatErrorForLogging(error: unknown): {
    message: string;
    code?: string;
    stack?: string;
    details?: unknown;
} {
    const message = getErrorMessage(error);
    const code = getErrorCode(error);

    const formatted: {
        message: string;
        code?: string;
        stack?: string;
        details?: unknown;
    } = { message };

    if (code) {
        formatted.code = code;
    }

    if (isError(error) && error.stack) {
        formatted.stack = error.stack;
    }

    // EN: Include original error for debugging
    // VI: Bao gồm error gốc để debug
    if (typeof error === 'object' && error !== null) {
        formatted.details = error;
    }

    return formatted;
}
