"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isClientCompiler = exports.setupServerHooks = exports.startDevServer = exports.getDevServerOptions = void 0;
const lodash_1 = require("@modern-js/utils/lodash");
const logger_1 = require("./logger");
const constants_1 = require("./constants");
const prodServer_1 = require("./prodServer");
const getDevServerOptions = async ({ builderConfig, serverOptions, port, }) => {
    var _a, _b, _c, _d, _e, _f;
    const { applyOptionsChain } = await Promise.resolve().then(() => __importStar(require('@modern-js/utils')));
    const { merge: deepMerge } = await Promise.resolve().then(() => __importStar(require('@modern-js/utils/lodash')));
    const defaultDevConfig = deepMerge({
        hot: (_b = (_a = builderConfig.dev) === null || _a === void 0 ? void 0 : _a.hmr) !== null && _b !== void 0 ? _b : true,
        watch: true,
        client: {
            port: port.toString(),
        },
        port,
        liveReload: (_d = (_c = builderConfig.dev) === null || _c === void 0 ? void 0 : _c.hmr) !== null && _d !== void 0 ? _d : true,
        devMiddleware: {
            writeToDisk: (file) => !file.includes('.hot-update.'),
        },
        https: (_e = builderConfig.dev) === null || _e === void 0 ? void 0 : _e.https,
    }, 
    // merge devServerOptions from serverOptions
    serverOptions.dev);
    const devConfig = applyOptionsChain(defaultDevConfig, (_f = builderConfig.tools) === null || _f === void 0 ? void 0 : _f.devServer, {}, deepMerge);
    const defaultConfig = (0, prodServer_1.getServerOptions)(builderConfig);
    const config = serverOptions.config
        ? (0, lodash_1.merge)({}, defaultConfig, serverOptions.config)
        : defaultConfig;
    return { config, devConfig };
};
exports.getDevServerOptions = getDevServerOptions;
async function startDevServer(options, createDevServer, { compiler, printURLs = true, strictPort = false, serverOptions = {}, } = {}) {
    var _a, _b, _c, _d, _e;
    logger_1.logger.info('Starting dev server...');
    if (!process.env.NODE_ENV) {
        process.env.NODE_ENV = 'development';
    }
    const { getPort, isFunction, DEFAULT_DEV_HOST } = await Promise.resolve().then(() => __importStar(require('@modern-js/utils')));
    const builderConfig = options.context.config;
    const port = await getPort(((_a = builderConfig.dev) === null || _a === void 0 ? void 0 : _a.port) || constants_1.DEFAULT_PORT, {
        strictPort,
    });
    const host = typeof (serverOptions === null || serverOptions === void 0 ? void 0 : serverOptions.dev) === 'object' && ((_b = serverOptions === null || serverOptions === void 0 ? void 0 : serverOptions.dev) === null || _b === void 0 ? void 0 : _b.host)
        ? (_c = serverOptions === null || serverOptions === void 0 ? void 0 : serverOptions.dev) === null || _c === void 0 ? void 0 : _c.host
        : DEFAULT_DEV_HOST;
    const https = typeof (serverOptions === null || serverOptions === void 0 ? void 0 : serverOptions.dev) === 'object' && ((_d = serverOptions === null || serverOptions === void 0 ? void 0 : serverOptions.dev) === null || _d === void 0 ? void 0 : _d.https)
        ? Boolean((_e = serverOptions === null || serverOptions === void 0 ? void 0 : serverOptions.dev) === null || _e === void 0 ? void 0 : _e.https)
        : false;
    options.context.devServer = {
        hostname: host,
        port,
        https,
    };
    const server = await createDevServer(options, port, serverOptions, compiler);
    await options.context.hooks.onBeforeStartDevServerHook.call();
    (0, logger_1.debug)('listen dev server');
    await server.init();
    return new Promise(resolve => {
        server.listen({
            host,
            port,
        }, async (err) => {
            var _a;
            if (err) {
                throw err;
            }
            (0, logger_1.debug)('listen dev server done');
            const { getAddressUrls } = await Promise.resolve().then(() => __importStar(require('@modern-js/utils')));
            const protocol = https ? 'https' : 'http';
            let urls = getAddressUrls(protocol, port, (_a = builderConfig.dev) === null || _a === void 0 ? void 0 : _a.host);
            if (printURLs) {
                if (isFunction(printURLs)) {
                    urls = printURLs(urls);
                    if (!Array.isArray(urls)) {
                        throw new Error('Please return an array in the `printURLs` function.');
                    }
                }
                await (0, prodServer_1.printServerURLs)(urls, 'Dev server');
            }
            await options.context.hooks.onAfterStartDevServerHook.call({ port });
            resolve({
                port,
                urls: urls.map(item => item.url),
                server,
            });
        });
    });
}
exports.startDevServer = startDevServer;
const setupServerHooks = (compiler, hookCallbacks) => {
    if (compiler.name === 'server') {
        return;
    }
    const { compile, invalid, done } = compiler.hooks;
    compile.tap('modern-dev-server', hookCallbacks.onInvalid);
    invalid.tap('modern-dev-server', hookCallbacks.onInvalid);
    done.tap('modern-dev-server', hookCallbacks.onDone);
};
exports.setupServerHooks = setupServerHooks;
const isClientCompiler = (compiler) => {
    const { target } = compiler.options;
    // if target not contains `node` or `webworker`, it's a client compiler
    if (target) {
        if (Array.isArray(target)) {
            return !target.includes('node') && !target.includes('webworker');
        }
        return target !== 'node' && target !== 'webworker';
    }
    return compiler.name === 'client';
};
exports.isClientCompiler = isClientCompiler;
