"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const mime_types_1 = __importDefault(require("mime-types"));
const url_1 = __importDefault(require("url"));
const fsExists = p => {
    return new Promise(resolve => {
        fs_1.default.exists(p, exists => resolve(exists));
    });
};
exports.rule = ({ ruleService, mockDataService, profileService, }) => {
    return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
        if (ctx.ignore) {
            yield next();
            return;
        }
        if (!profileService.enableRule(ctx.userID)) {
            yield next();
            return;
        }
        const { userID } = ctx;
        const { req } = ctx;
        const { method, url } = req;
        const urlObj = url_1.default.parse(url);
        const processRule = ruleService.getProcessRule(userID, method, urlObj);
        if (!processRule) {
            yield next();
            return;
        }
        ctx.res.setHeader('zan-proxy-rule-match', processRule.match);
        if (urlObj.pathname && mime_types_1.default.lookup(urlObj.pathname)) {
            ctx.res.setHeader('Content-Type', mime_types_1.default.lookup(urlObj.pathname));
        }
        // 规则的响应头先缓存在这里
        const resHeaders = {};
        for (const action of processRule.actionList) {
            const { data } = action;
            switch (action.type) {
                case 'mockData':
                    const { dataId } = data;
                    const content = yield mockDataService.getDataFileContent(userID, dataId);
                    const contentType = yield mockDataService.getDataFileContentType(userID, dataId);
                    ctx.res.body = content;
                    ctx.res.setHeader('Content-Type', contentType);
                    break;
                case 'addRequestHeader':
                    ctx.req.headers[data.headerKey] = data.headerValue;
                    break;
                case 'addResponseHeader':
                    resHeaders[data.headerKey] = data.headerValue;
                    break;
                case 'empty':
                    ctx.res.body = '';
                    break;
                case 'redirect':
                    const target = profileService.calcPath(userID, urlObj.href, processRule.match, data.target);
                    if (!target) {
                        continue;
                    }
                    ctx.res.setHeader('zan-proxy-target', target);
                    if (target.startsWith('http') || target.startsWith('ws')) {
                        ctx.req.url = target;
                    }
                    else {
                        const exists = yield fsExists(target);
                        if (exists) {
                            ctx.res.body = fs_1.default.createReadStream(target);
                        }
                        else {
                            ctx.res.body = `target ${target} does not exist`;
                            ctx.res.statusCode = 404;
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        yield next();
        Object.keys(resHeaders).forEach(headerKey => {
            ctx.res.setHeader(headerKey, resHeaders[headerKey]);
        });
    });
};
//# sourceMappingURL=rule.js.map