import { getInitializer } from '../helpers.js';
export const DecoratorDriver = {
    /** Add a provider { provide, useClass } to a decorator array. */
    addDecoratorAdapter(sourceFile, moduleName, decoratorName, propertyName, provide, adapter) {
        const args = DecoratorDriver.getClassDecoratorArguments(sourceFile, moduleName, decoratorName);
        const prop = args.getProperty(propertyName);
        const array = getInitializer(prop);
        array.addElement(`\n{\n  provide : ${provide},\n  useClass: ${adapter}\n}`, { useNewLines: true });
    },
    /** Add an element to a decorator array property (e.g., providers, imports). */
    addModuleDecoratorProperty(sourceFile, moduleName, decoratorName, propertyName, module) {
        if (DecoratorDriver.hasModuleDecoratorProperty(sourceFile, moduleName, decoratorName, propertyName, module)) {
            return;
        }
        const args = DecoratorDriver.getClassDecoratorArguments(sourceFile, moduleName, decoratorName);
        const prop = args.getProperty(propertyName);
        const array = getInitializer(prop);
        array.addElement(module, { useNewLines: true });
    },
    /** Change the useClass of a provider in a decorator array property. */
    changeModuleDecoratorPropertyAdapter(sourceFile, moduleName, decoratorName, propertyName, provide, adapter) {
        const args = DecoratorDriver.getClassDecoratorArguments(sourceFile, moduleName, decoratorName);
        const prop = args.getProperty(propertyName);
        const array = getInitializer(prop);
        for (const value of array.getElements()) {
            if (value.getKindName() !== 'ObjectLiteralExpression')
                continue;
            const obj = value;
            const provideProp = obj.getProperty('provide');
            if (provideProp &&
                getInitializer(provideProp)?.getText() === provide) {
                const useClassProp = obj.getProperty('useClass');
                useClassProp?.setInitializer(adapter);
            }
        }
    },
    getClassDecoratorArguments(sourceFile, className, decoratorName) {
        const cls = sourceFile.getClass(className);
        const decorator = cls?.getDecorator(decoratorName);
        return decorator.getArguments()[0];
    },
    /** Check if a decorator array property already contains a value. */
    hasModuleDecoratorProperty(sourceFile, moduleName, decoratorName, propertyName, module) {
        const args = DecoratorDriver.getClassDecoratorArguments(sourceFile, moduleName, decoratorName);
        const prop = args.getProperty(propertyName);
        const array = getInitializer(prop);
        return array.getElements().some((el) => el.getText() === module);
    },
    /** Remove a provider from a decorator array by its provide value. */
    removeDecoratorAdapter(sourceFile, moduleName, decoratorName, propertyName, provide) {
        const args = DecoratorDriver.getClassDecoratorArguments(sourceFile, moduleName, decoratorName);
        const prop = args.getProperty(propertyName);
        const array = getInitializer(prop);
        const elements = array.getElements();
        for (let i = elements.length - 1; i >= 0; i--) {
            const el = elements[i];
            if (el.getKindName() !== 'ObjectLiteralExpression')
                continue;
            const obj = el;
            const provideProp = obj.getProperty('provide');
            if (provideProp &&
                getInitializer(provideProp)?.getText() === provide) {
                array.removeElement(i);
            }
        }
    },
};
