/*
 * @adonisjs/core
 *
 * (c) AdonisJS
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
import { parseImports } from 'parse-imports';
/**
 * The "parseBindingReference" method can be used to parse a binding references
 * similar to route controller binding value or event listener binding value.
 *
 * See the following examples to understand how this function works.
 *
 * ### Magic strings
 * ```ts
 * parseBindingReference('#controllers/home_controller')
 * // returns { moduleNameOrPath: '#controllers/home_controller', method: 'handle' }

 * parseBindingReference('#controllers/home_controller.index')
 * // returns { moduleNameOrPath: '#controllers/home_controller', method: 'index' }

 * parseBindingReference('#controllers/home.controller.index')
 * // returns { moduleNameOrPath: '#controllers/home.controller', method: 'index' }
 * ```
 *
 * ### Class reference
 * ```ts
 * class HomeController {}
 *
 * parseBindingReference([HomeController])
 * // returns { moduleNameOrPath: 'HomeController', method: 'handle' }

 * parseBindingReference([HomeController, 'index'])
 * // returns { moduleNameOrPath: 'HomeController', method: 'index' }
 * ```
 *
 * ### Lazy import reference
 * ```ts
 * const HomeController = () => import('#controllers/home_controller')
 *
 * parseBindingReference([HomeController])
 * // returns { moduleNameOrPath: '#controllers/home_controller', method: 'handle' }

 * parseBindingReference([HomeController, 'index'])
 * // returns { moduleNameOrPath: 'controllers/home_controller', method: 'index' }
 * ```
 */
export async function parseBindingReference(binding) {
    /**
     * The binding reference is a magic string. It might not have method
     * name attached to it. Therefore we split the string and attempt
     * to find the method or use the default method name "handle".
     */
    if (typeof binding === 'string') {
        const tokens = binding.split('.');
        if (tokens.length === 1) {
            return { moduleNameOrPath: binding, method: 'handle' };
        }
        return { method: tokens.pop(), moduleNameOrPath: tokens.join('.') };
    }
    const [bindingReference, method] = binding;
    /**
     * Parsing the binding reference for dynamic imports and using its
     * import value.
     */
    const imports = [...(await parseImports(bindingReference.toString()))];
    const importedModule = imports.find(($import) => $import.isDynamicImport && $import.moduleSpecifier.value);
    if (importedModule) {
        return {
            moduleNameOrPath: importedModule.moduleSpecifier.value,
            method: method || 'handle',
        };
    }
    /**
     * Otherwise using the name of the binding reference.
     */
    return {
        moduleNameOrPath: bindingReference.name,
        method: method || 'handle',
    };
}
