"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = void 0;
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const formatting_1 = require("../../utils/formatting");
const module_declarator_1 = require("../../utils/module.declarator");
const module_finder_1 = require("../../utils/module.finder");
const name_parser_1 = require("../../utils/name.parser");
const source_root_helpers_1 = require("../../utils/source-root.helpers");
const defaults_1 = require("../defaults");
const ts = require("ts-morph");
const module_import_declarator_1 = require("../../utils/module-import.declarator");
const strings_1 = require("@angular-devkit/core/src/utils/strings");
const ELEMENT_METADATA = 'controllers';
const ELEMENT_TYPE = 'controller';
function main(options) {
    options = transform(options);
    return (tree, context) => {
        if (!(0, source_root_helpers_1.isInSvrRootDirectory)(tree, [])) {
            throw new schematics_1.SchematicsException('This command must run in server root dir.');
        }
        return (0, schematics_1.branchAndMerge)((0, schematics_1.chain)([
            (0, source_root_helpers_1.mergeSourceRoot)(options),
            addDeclarationToParentIndex(options),
            (0, schematics_1.mergeWith)(generate(options)),
        ]))(tree, context);
    };
}
exports.main = main;
function transform(source) {
    const target = Object.assign({}, source);
    target.metadata = ELEMENT_METADATA;
    target.type = ELEMENT_TYPE;
    const location = new name_parser_1.NameParser().parse(target);
    target.name = (0, formatting_1.normalizeToKebabOrSnakeCase)(location.name);
    target.path = (0, formatting_1.normalizeToKebabOrSnakeCase)(location.path);
    target.language =
        target.language !== undefined ? target.language : defaults_1.DEFAULT_LANGUAGE;
    target.path = target.flat
        ? target.path
        : (0, core_1.join)(target.path, target.name);
    target.module = ('/' + defaults_1.DEFAULT_CUSTOMIZE_INDEX);
    return target;
}
function generate(options) {
    return (context) => (0, schematics_1.apply)((0, schematics_1.url)((0, core_1.join)('./files', options.language)), [
        options.spec ? (0, schematics_1.noop)() : (0, schematics_1.filter)((path) => !path.endsWith('.spec.ts')),
        (0, schematics_1.template)(Object.assign(Object.assign({}, core_1.strings), options)),
        (0, schematics_1.move)(options.path),
    ])(context);
}
function addDeclarationToModule(options) {
    return (tree) => {
        if (options.skipImport !== undefined && options.skipImport) {
            return tree;
        }
        options.module = new module_finder_1.ModuleFinder(tree).find({
            name: options.name,
            path: options.path,
        });
        if (!options.module) {
            return tree;
        }
        const content = tree.read(options.module).toString();
        const declarator = new module_declarator_1.ModuleDeclarator();
        tree.overwrite(options.module, declarator.declare(content, options));
        return tree;
    };
}
function addDeclarationToParentIndex(options) {
    return (tree) => {
        const controllerPath = (0, core_1.join)(options.path, `${options.name}.${ELEMENT_TYPE}.${options.language}`);
        if (tree.get(controllerPath)) {
            throw new schematics_1.SchematicsException(`${controllerPath} is exist.`);
        }
        options.hasGenerated = false;
        if (tree.get((0, core_1.join)(defaults_1.DEFAULT_GENERATED_DIR, options.name, `${options.name}.${ELEMENT_TYPE}.${options.language}`))) {
            options.hasGenerated = true;
        }
        if (options.skipImport !== undefined && options.skipImport) {
            return tree;
        }
        const fileRef = tree.get(defaults_1.DEFAULT_CUSTOMIZE_INDEX);
        if (!fileRef) {
            throw new schematics_1.SchematicsException(`${defaults_1.DEFAULT_CUSTOMIZE_INDEX} is not exist.`);
        }
        const tsProject = new ts.Project({
            manipulationSettings: {
                indentationText: ts.IndentationText.TwoSpaces,
            },
        });
        const tsFile = tsProject.addSourceFileAtPath(defaults_1.DEFAULT_CUSTOMIZE_INDEX);
        const expressionNode = tsFile.getDefaultExportSymbolOrThrow().getDeclarations()
            .find(node => node.getKind() === ts.SyntaxKind.ExportAssignment);
        const arrayLiteralExpression = expressionNode.getFirstChildByKindOrThrow(ts.SyntaxKind.ArrayLiteralExpression);
        const imports = new module_import_declarator_1.ModuleImportDeclarator();
        options = computeSymbol(options);
        arrayLiteralExpression.getFullText().includes(options.symbol);
        arrayLiteralExpression.addElement(options.symbol);
        const content = imports.declare(tsFile.getFullText(), options);
        tree.overwrite(defaults_1.DEFAULT_CUSTOMIZE_INDEX, content);
        return tree;
    };
}
function computeSymbol(options) {
    const target = Object.assign({}, options);
    if (options.className) {
        target.symbol = options.className;
    }
    else if (options.type !== undefined) {
        target.symbol = (0, strings_1.classify)(options.name).concat((0, strings_1.capitalize)(options.type));
    }
    else {
        target.symbol = (0, strings_1.classify)(options.name);
    }
    return target;
}
