import { type Language, languages } from "./language-list";

/**
 * Valid language code types that can be used for filtering
 */
export type LanguageCodeType = "1" | "2" | "2T" | "2B" | "3" | 1 | 2 | 3;

/**
 * Valid criteria for searching languages
 */
export type LanguageCriteria = keyof Language;

// Re-export the Language interface for convenience
export type { Language } from "./language-list";

/**
 * Returns all available languages
 * @returns Array of all language objects
 * @example
 * ```typescript
 * const allLangs = allLanguages();
 * console.log(allLangs.length); // 184
 * ```
 */
export function allLanguages(): readonly Language[] {
	return languages;
}

/**
 * Checks if a language exists based on given criteria and value
 * @param criteria - The property to search by (e.g., 'name', '1', '2', etc.)
 * @param value - The value to search for
 * @returns True if language exists, false otherwise
 * @example
 * ```typescript
 * const exists = hasLanguage('1', 'en'); // true
 * const notExists = hasLanguage('name', 'Klingon'); // false
 * ```
 */
export function hasLanguage(
	criteria: LanguageCriteria,
	value: string,
): boolean {
	return findBy(criteria, value) !== undefined;
}

/**
 * Gets all language codes of a specific type
 * @param type - The code type to retrieve ('1', '2', '2T', '2B', '3', or numeric equivalents)
 * @returns Array of language codes, or undefined if invalid type
 * @example
 * ```typescript
 * const iso6391Codes = getCodes('1'); // ['ab', 'aa', 'af', ...]
 * const iso6392Codes = getCodes('2'); // ['abk', 'aar', 'afr', ...]
 * ```
 */
export function getCodes(type: LanguageCodeType): string[] | undefined {
	if (!isValidType(type)) {
		return undefined;
	}

	const stringType = String(type) as keyof Language;
	return languages.map((language: Language) => language[stringType]);
}

/**
 * Gets all language names (English or local)
 * @param useLocal - If true, returns local names; if false, returns English names
 * @returns Array of language names
 * @example
 * ```typescript
 * const englishNames = getNames(false); // ['Abkhaz', 'Afar', 'Afrikaans', ...]
 * const localNames = getNames(true); // ['Аҧсуа', 'Afaraf', 'Afrikaans', ...]
 * ```
 */
export function getNames(useLocal = false): string[] {
	return languages.map((language: Language) =>
		useLocal ? language.local : language.name,
	);
}

/**
 * Finds a language by specific criteria and value
 * @param criteria - The property to search by
 * @param value - The value to search for
 * @returns The matching language object, or undefined if not found
 * @example
 * ```typescript
 * const english = findBy('1', 'en');
 * // { name: 'English', local: 'English', '1': 'en', '2': 'eng', ... }
 *
 * const spanish = findBy('name', 'Spanish');
 * // { name: 'Spanish', local: 'Español', '1': 'es', '2': 'spa', ... }
 * ```
 */
export function findBy(
	criteria: LanguageCriteria,
	value: string,
): Language | undefined {
	return languages.find((language: Language) => language[criteria] === value);
}

/**
 * Validates if the given type is a valid language code type
 * @param type - The type to validate
 * @returns True if valid, false otherwise
 * @internal
 */
function isValidType(type: unknown): type is LanguageCodeType {
	const validTypes: (string | number)[] = [1, 2, 3, "1", "2", "2B", "2T", "3"];
	return validTypes.includes(type as string | number);
}

/**
 * Main API object containing all language utility functions
 * @deprecated Use named exports instead
 */
export const langs = {
	/** @deprecated Use allLanguages() instead */
	all: allLanguages,
	/** @deprecated Use hasLanguage() instead */
	has: hasLanguage,
	/** @deprecated Use getCodes() instead */
	codes: getCodes,
	/** @deprecated Use getNames() instead */
	names: getNames,
	/** @deprecated Use findBy() instead */
	where: findBy,
} as const;

// Default export for backward compatibility
export default langs;
