"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", { value: true });
const querystring_1 = require("querystring");
const shared_1 = require("@intlify/shared");
const Dependency = require('webpack/lib/Dependency'); // eslint-disable-line @typescript-eslint/no-var-requires
const NullFactory = require('webpack/lib/NullFactory'); // eslint-disable-line @typescript-eslint/no-var-requires
const PLUGIN_ID = 'IntlifyVuePlugin';
class VueComponentDependency extends Dependency {
    constructor(script /* webpack.Dependency | undefined, */, template /* webpack.Dependency | undefined, */, values, statement) {
        super();
        this.script = script;
        this.template = template;
        this.values = values;
        this.statement = statement;
    }
    // @ts-ignore
    get type() {
        return 'harmony export expression';
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    getExports(moduleGraph /* webpack.ModuleGraph */) {
        return {
            exports: ['default'],
            dependencies: undefined
        };
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    updateHash(hash, context) {
        super.updateHash(hash, context);
        const scriptModule = this.script;
        hash.update((scriptModule &&
            (!scriptModule.buildMeta || scriptModule.buildMeta.exportsType)) + '');
        hash.update((scriptModule && scriptModule.id) + '');
        const templateModule = this.template;
        hash.update((templateModule &&
            (!templateModule.buildMeta || templateModule.buildMeta.exportsType)) +
            '');
        hash.update((templateModule && templateModule.id) + '');
    }
}
function stringifyObj(obj) {
    return `Object({${Object.keys(obj)
        .map(key => {
        const code = obj[key];
        return `${JSON.stringify(key)}:${toCode(code)}`;
    })
        .join(',')}})`;
}
function toCode(code) {
    if (code === null) {
        return 'null';
    }
    if (code === undefined) {
        return 'undefined';
    }
    if (shared_1.isString(code)) {
        return JSON.stringify(code);
    }
    if (shared_1.isRegExp(code) && code.toString) {
        return code.toString();
    }
    if (shared_1.isFunction(code) && code.toString) {
        return '(' + code.toString() + ')';
    }
    if (shared_1.isObject(code)) {
        return stringifyObj(code);
    }
    return code + '';
}
function generateCode(dep, importVar) {
    const injectionCodes = [''];
    Object.keys(dep.values).forEach(key => {
        const code = dep.values[key];
        if (shared_1.isFunction(code)) {
            injectionCodes.push(`${importVar}.${key} = ${JSON.stringify(code(dep))}`);
        }
        else {
            injectionCodes.push(`${importVar}.${key} = ${toCode(code)}`);
        }
    });
    let ret = injectionCodes.join('\n');
    ret = ret.length > 0 ? `\n${ret}\n` : '';
    return (ret += `/* harmony default export */ __webpack_exports__["default"] = (${importVar});`);
}
class VueComponentDependencyTemplate {
    apply(dep, source /* webpack.sources.ReplaceSource */) {
        const repleacements = source.replacements;
        const orgReplace = repleacements[repleacements.length - 1];
        const code = generateCode(dep, 'component.exports');
        // console.log('generateCode', code, dep.statement, orgReplace)
        source.replace(orgReplace.start, orgReplace.end, code);
    }
}
VueComponentDependency.Template = VueComponentDependencyTemplate;
function getScriptBlockModule(parser /* webpack.javascript.JavascriptParser */) {
    return parser.state.current.dependencies.find((dep) => {
        const req = dep.userRequest || dep.request;
        if (req && dep.originModule) {
            const query = querystring_1.parse(req);
            return query.type === 'script' && query.lang === 'js';
        }
        else {
            return false;
        }
    });
}
function getTemplateBlockModule(parser /* webpack.javascript.JavascriptParser */) {
    return parser.state.current.dependencies.find((dep) => {
        const req = dep.userRequest || dep.request;
        if (req && dep.originModule) {
            const query = querystring_1.parse(req);
            return query.type === 'template';
        }
        else {
            return false;
        }
    });
}
function toVueComponentDependency(parser /* webpack.javascript.JavascriptParser */, values) {
    return function vueComponentDependencyw(statement) {
        // console.log('toVueComponentDependency##statement', statement)
        const dep = new VueComponentDependency(getScriptBlockModule(parser), getTemplateBlockModule(parser), values, statement);
        // dep.loc = statement.loc
        parser.state.current.addDependency(dep);
        return true;
    };
}
class IntlifyVuePlugin {
    constructor(injections = {}) {
        this.injections = injections;
    }
    apply(compiler) {
        const injections = this.injections;
        compiler.hooks.compilation.tap(PLUGIN_ID, (compilation, { normalModuleFactory }) => {
            compilation.dependencyFactories.set(
            // @ts-ignore
            VueComponentDependency, new NullFactory());
            compilation.dependencyTemplates.set(
            // @ts-ignore
            VueComponentDependency, 
            // @ts-ignore
            new VueComponentDependency.Template());
            const handler = (parser /* webpack.javascript.JavascriptParser */) => {
                parser.hooks.exportExpression.tap(PLUGIN_ID, (statement, declaration) => {
                    if (parser.state.module.resource.endsWith('.vue') &&
                        declaration.object.name === 'component' &&
                        declaration.property.name === 'exports') {
                        // console.log('exportExpression', statement, declaration)
                        return toVueComponentDependency(parser, injections)(statement);
                    }
                });
            };
            normalModuleFactory.hooks.parser
                .for('javascript/auto')
                .tap(PLUGIN_ID, handler);
            normalModuleFactory.hooks.parser
                .for('javascript/dynamic')
                .tap(PLUGIN_ID, handler);
            normalModuleFactory.hooks.parser
                .for('javascript/esm')
                .tap(PLUGIN_ID, handler);
        });
    }
}
exports.default = IntlifyVuePlugin;
/* eslint-enable @typescript-eslint/no-explicit-any */
