import { isString } from 'lodash-es';

/** Type definition for constructor functions */
type Class<T> = new (...args: any[]) => T; // eslint-disable-line @typescript-eslint/no-explicit-any

/**
 * Utility class for validating arguments and state conditions
 * 
 * Provides methods to validate function arguments and application state
 * with consistent error handling and messaging.
 */
export default class ValidationUtils {

    /**
     * Validate that a state condition is true
     * 
     * @param condition - The condition to validate
     * @param message - Error message to throw if condition is false
     * @throws {Error} If condition is false
     * 
     * @example
     * ```typescript
     * ValidationUtils.validateState(wallet.isInitialized, 'Wallet must be initialized');
     * ```
     */
    public static validateState(condition: boolean, message: string): void {
        if (!condition) {
            throw new Error(`Invalid State: ${message}`);
        }
    }

    /**
     * Validate that an argument condition is true
     * 
     * @param condition - The condition to validate
     * @param argumentName - Name of the argument being validated
     * @param message - Optional additional error message
     * @throws {Error} If condition is false
     * 
     * @example
     * ```typescript
     * ValidationUtils.validateArgument(
     *   typeof amount === 'number',
     *   'amount',
     *   'must be a number'
     * );
     * ```
     */
    public static validateArgument(condition: boolean, argumentName: string, message = ""): void {
        if (!condition) {
            throw new Error(`Invalid Argument: ${argumentName}. ${message}`);
        }
    }

    /**
     * Validate that an argument is of the expected type
     * 
     * @param argument - The argument to validate
     * @param type - Expected type (string name or constructor function)
     * @param argumentName - Name of the argument being validated
     * @throws {TypeError} If argument is not of expected type
     * 
     * @example
     * ```typescript
     * ValidationUtils.validateArgumentType(buffer, 'Buffer', 'data');
     * ValidationUtils.validateArgumentType(wallet, Wallet, 'wallet');
     * ValidationUtils.validateArgumentType(amount, 'number', 'amount');
     * ```
     */
    public static validateArgumentType<T>(argument: unknown, type: string | Class<T>, argumentName?: string): void {
        argumentName = argumentName || '(unknown name)';
        if (isString(type)) {
            if (type === 'Buffer') {
                if (!Buffer.isBuffer(argument)) {
                    throw new TypeError(`Invalid Argument for ${argumentName}, expected ${type} but got ${typeof argument}`);
                }
            } else if (typeof argument !== type) {
                throw new TypeError(`Invalid Argument for ${argumentName}, expected ${type} but got ${typeof argument}`);
            }
        } else {
            if (!(argument instanceof type)) {
                throw new TypeError(`Invalid Argument for ${argumentName}, expected ${type} but got ${typeof argument}`);
            }
        }
    }
}
