"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
const sequelize_1 = require("sequelize");
const types_1 = require("../types");
const core_1 = require("@asapjs/core");
const router_1 = require("@asapjs/router");
class ExtendableDto {
    constructor() {
        this.init = () => {
            const dtoName = this.constructor.name;
            (0, router_1.addScheme)({ name: dtoName, data: this.generateScheme() });
        };
        this.map = (data) => {
            const types = (0, types_1.getTypesData)(this);
            const properties = Object.assign({}, types);
            const o = (data === null || data === void 0 ? void 0 : data.dataValues) || data;
            const isArray = Array.isArray(o);
            if (isArray) {
                return o.map((item) => this.map(item));
            }
            return Object.keys(properties).reduce((p, key) => {
                var _a, _b;
                const property = properties[key];
                if (property.__name === 'dto') {
                    // DTO TYPE인데 toSequelize가 없을 경우
                    if (!property.toSequelize) {
                        core_1.logger.error(`@asapjs/sequelize :: @TypeIs.DTO - ${key}에서 에러가 발생했습니다.`);
                        process.exit(1);
                    }
                    const data = property.toSequelize();
                    if (!data.dto) {
                        core_1.logger.error(`@asapjs/sequelize :: @TypeIs.DTO - ${key}에 dto가 전달되지 않았습니다..`);
                        process.exit(1);
                    }
                    p[key] = !!(o === null || o === void 0 ? void 0 : o[key]) ? new data.dto().map(o === null || o === void 0 ? void 0 : o[key]) : null;
                }
                else if (property.__name === 'query') {
                    p[key] = (_a = property === null || property === void 0 ? void 0 : property.fixValue) === null || _a === void 0 ? void 0 : _a.call(property, o === null || o === void 0 ? void 0 : o[key]);
                }
                else {
                    p[key] = ((_b = property === null || property === void 0 ? void 0 : property.fixValue) === null || _b === void 0 ? void 0 : _b.call(property, o === null || o === void 0 ? void 0 : o[key])) || (o === null || o === void 0 ? void 0 : o[key]);
                }
                return p;
            }, {});
        };
        this.pagingMap = (data) => {
            const o = data.data;
            return Object.assign(Object.assign({}, data), { data: o.map((item) => this.map(item)) });
        };
        this.middleware = (as, user, extraAs) => {
            const modelInfo = Reflect.getMetadata('sequelize::dtoInfo', this);
            const types = (0, types_1.getTypesData)(this);
            const extraAsData = extraAs ? [...extraAs, as].filter((v) => !!v) : as ? [as] : [];
            const attributes = [];
            const include = [];
            if (types) {
                // DTO와 QUERY TYPE은 따로 Include 필요하기 때문에 필터링
                const attributesOptions = Object.entries(types).filter(([key, v]) => !['dto', 'query'].includes(v.__name));
                if (attributesOptions) {
                    attributesOptions.forEach(([key, v]) => {
                        attributes.push(key);
                    });
                }
                // QUERY TYPE 필터링
                const queryOptions = Object.entries(types).filter(([key, v]) => v.__name === 'query');
                if (queryOptions) {
                    queryOptions.forEach(([key, v]) => {
                        // QUERY TYPE인데 toSequelize가 없을 경우
                        if (!v.toSequelize) {
                            core_1.logger.error(`@asapjs/sequelize :: @TypeIs.QUERY - ${key}에서 에러가 발생했습니다.`);
                            process.exit(1);
                        }
                        if (!v.toSequelize().query) {
                            core_1.logger.error(`@asapjs/sequelize :: @TypeIs.QUERY - ${key}에 query가 전달되지 않았습니다..`);
                            process.exit(1);
                        }
                        const association = extraAsData.length >= 2 ? '`' + `${extraAsData.join('->')}` + '`' : as || modelInfo.defineTable.name;
                        attributes.push([
                            (0, sequelize_1.literal)(v.toSequelize().query({
                                association: association,
                                user,
                            })),
                            key,
                        ]);
                    });
                }
                // DTO TYPE 필터링
                const connectOptions = Object.entries(types).filter(([key, v]) => v.__name === 'dto');
                if (connectOptions) {
                    connectOptions.forEach(([key, v]) => {
                        // DTO TYPE인데 toSequelize가 없을 경우
                        if (!v.toSequelize) {
                            core_1.logger.error(`@asapjs/sequelize :: @TypeIs.DTO - ${key}에서 에러가 발생했습니다.`);
                            process.exit(1);
                        }
                        const data = v.toSequelize();
                        if (!data.dto) {
                            core_1.logger.error(`@asapjs/sequelize :: @TypeIs.DTO - ${key}에 dto가 전달되지 않았습니다..`);
                            process.exit(1);
                        }
                        include.push(new data.dto().middleware((data === null || data === void 0 ? void 0 : data.as) || key, user, extraAsData));
                    });
                }
            }
            const result = {
                model: modelInfo.defineTable,
                attributes,
            };
            if (as)
                result.as = as;
            if (include.length > 0)
                result.include = include;
            return result;
        };
        this.generateScheme = () => {
            const types = (0, types_1.getTypesData)(this);
            const data = Object.keys(types).reduce((p, key) => {
                var _a, _b;
                const property = types[key];
                if (property.toSwagger) {
                    p[key] = property.toSwagger() || null;
                }
                else {
                    core_1.logger.warn(`@asapjs/sequelize :: TypeIs.${(_b = (_a = property === null || property === void 0 ? void 0 : property.__name) === null || _a === void 0 ? void 0 : _a.toUpperCase) === null || _b === void 0 ? void 0 : _b.call(_a)}에 toSwagger가 정의되지 않았습니다.`);
                    p[key] = null;
                }
                return p;
            }, {});
            return {
                type: 'object',
                properties: data,
            };
        };
        this.swagger = () => {
            const dtoName = this.constructor.name;
            return {
                $ref: (0, router_1.generateSchemeRefWithName)(dtoName),
            };
        };
    }
}
exports.default = ExtendableDto;
ExtendableDto.isInitlized = false;
//# sourceMappingURL=ExtendableDto.js.map