import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
	return twMerge(clsx(inputs));
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, 'child'> : T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, 'children'> : T;
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };

export function createQueryParams(
	data: Record<string, string | string[] | number | boolean | undefined | null>
) {
	const params = new URLSearchParams();

	for (const [key, value] of Object.entries(data)) {
		if (value === undefined || value === null) continue;

		if (Array.isArray(value)) {
			value.forEach((item) => {
				if (item !== null && item !== undefined) {
					params.append(key, String(item));
				}
			});
		} else {
			params.append(key, String(value));
		}
	}

	return params;
}

export function formatFileSize(bytes: number, decimals = 1, binary = true) {
	if (!bytes) return '0 B';

	// Use 1024 for binary (default) or 1000 for decimal
	const divisor = binary ? 1024 : 1000;

	// Units for binary and decimal representations
	const units = binary
		? ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
		: ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

	// Find the appropriate unit
	const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(divisor)), units.length - 1);
	const size = bytes / Math.pow(divisor, exponent);

	// Format the number with appropriate decimals
	const formattedSize = size.toFixed(
		// Don't show decimals for bytes
		exponent === 0 ? 0 : decimals
	);

	return `${formattedSize} ${units[exponent]}`;
}

export function getFileType(filename: string) {
	const parts = filename.split('.');
	if (parts.length < 2) return 'UNKNOWN';
	const extension = parts[parts.length - 1];
	return extension.toUpperCase();
}

export const pluck = (array: [], key: string) => array.map((obj) => obj?.[key]);
