"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;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = __importDefault(require("lodash"));
const effects_1 = require("redux-saga/effects");
const typesafe_actions_1 = require("typesafe-actions");
const ACTIONS = __importStar(require("@/actions/builder/events"));
const MAIN_ACTIONS = __importStar(require("@/actions/builder/main"));
const index_1 = require("@/store/index");
const index_2 = require("./events/index");
const services_1 = require("./services");
const utils_1 = require("./utils");
/**
 * do update
 * update content and then init the new state for effect
 * @param effects
 * @param formattedData
 * @param hook
 * @returns
 */
function doUpdate(effects = [], formattedData, hook) {
    return __awaiter(this, void 0, void 0, function* () {
        let newPageContent = null;
        const { pageContent, application, extend } = index_1.store.getState().builder.main;
        if (!hook) {
            const content = index_1.store.getState().builder.main.content;
            const result = (0, index_2.updateContent)(effects, formattedData);
            const newContent = Object.assign(Object.assign({}, content), { schemas: result });
            newPageContent = lodash_1.default.cloneDeep(Object.assign(Object.assign({}, pageContent), { content: newContent }));
        }
        else {
            newPageContent = hook();
        }
        if (newPageContent) {
            const newFormatted = yield (0, services_1.initState)(newPageContent, {
                application: application,
                locale: index_1.store.getState().builder.header.locale,
                components: index_1.store.getState().builder.component.components,
                extendPage: lodash_1.default.cloneDeep(extend),
                file: index_1.store.getState().builder.main.file,
            });
            return { formattedData: newFormatted, pageContent: newPageContent };
        }
        return { formattedData, pageContent };
    });
}
function* handleAfterUpdate(actions) {
    const { pageContent, formattedData } = actions.payload;
    // current only variables need to match
    const cachedVariables = index_1.store.getState().applications.detail.file.variables.list || [];
    const localVariables = index_1.store.getState().builder.main.localVariables;
    const _a = pageContent.relations || {}, { variables = [] } = _a, rest = __rest(_a, ["variables"]);
    const relations = Object.assign(Object.assign({}, rest), { variables: localVariables.concat(variables).concat(cachedVariables) });
    // init & check relation (current only variables)
    const result = yield (0, effects_1.call)(services_1.getRelation, pageContent.content, relations);
    const newPageContent = Object.assign(Object.assign({}, pageContent), { content: Object.assign(Object.assign({}, pageContent.content), { relation: result.relation }) });
    yield (0, effects_1.put)(MAIN_ACTIONS.pushLocalVariables(result.data.variables));
    yield (0, effects_1.put)(MAIN_ACTIONS.pushStep(newPageContent));
    yield (0, effects_1.put)(MAIN_ACTIONS.updateContent(newPageContent));
    yield (0, effects_1.put)(MAIN_ACTIONS.pushFormatData(formattedData));
}
function* handleDropComponent(actions) {
    const { params } = actions.payload;
    const { formattedData, file } = index_1.store.getState().builder.main;
    const effects = (0, index_2.dropComponent)(params, {
        formattedData,
        file,
    });
    yield (0, effects_1.put)(MAIN_ACTIONS.selectComponent(effects[0]));
    const result = yield (0, effects_1.call)(doUpdate, effects, formattedData);
    yield (0, effects_1.put)(ACTIONS.afterUpdateComponent(result.pageContent, result.formattedData));
}
function* handleCopyComponent(actions) {
    const { params } = actions.payload;
    const { formattedData } = index_1.store.getState().builder.main;
    const effects = (0, index_2.copyComponents)([params], { formattedData });
    yield (0, effects_1.put)(MAIN_ACTIONS.selectComponent(effects[0]));
    const result = yield (0, effects_1.call)(doUpdate, effects, formattedData);
    yield (0, effects_1.put)(ACTIONS.afterUpdateComponent(result.pageContent, result.formattedData));
}
function* handleRemoveComponent(actions) {
    const { params } = actions.payload;
    const { formattedData, content } = index_1.store.getState().builder.main;
    const { updates = [], formattedData: formatted } = (0, index_2.removeComponents)([params], {
        content,
        formattedData,
    });
    const result = yield (0, effects_1.call)(doUpdate, updates, formatted);
    yield (0, effects_1.put)(MAIN_ACTIONS.selectComponent(null));
    yield (0, effects_1.put)(ACTIONS.afterUpdateComponent(result.pageContent, result.formattedData));
}
function* handleUpdateComponent(actions) {
    const { params } = actions.payload;
    // TODO:
    // component or page node
    if (params.name === 'page' && params.type === 'page') {
        yield (0, effects_1.put)(MAIN_ACTIONS.updatePageNode(Object.assign(Object.assign({}, (0, utils_1.pickNode)(params)), { children: [] })));
        const { pageContent, formattedData } = index_1.store.getState().builder.main;
        yield (0, effects_1.put)(ACTIONS.afterUpdateComponent(pageContent, formattedData));
    }
    else {
        const { formattedData } = index_1.store.getState().builder.main;
        yield (0, effects_1.put)(MAIN_ACTIONS.selectComponent(params));
        const _isNode = (0, index_2.isNode)(params);
        const result = _isNode
            ? yield (0, effects_1.call)(doUpdate, [params], formattedData)
            : yield (0, effects_1.call)(doUpdate, [params], formattedData, () => {
                const { pageContent, mock } = index_1.store.getState().builder.main;
                const result = (0, index_2.updateMockContent)([params], mock);
                const newContent = Object.assign(Object.assign({}, mock), { schemas: result });
                return lodash_1.default.cloneDeep(Object.assign(Object.assign({}, pageContent), { mock: newContent }));
            });
        yield (0, effects_1.put)(ACTIONS.afterUpdateComponent(result.pageContent, result.formattedData));
    }
}
function* handleVariableBind(actions) {
    const { keys, value } = actions.payload;
    const { selectedNode } = index_1.store.getState().builder.main;
    if (selectedNode) {
        const clonedProps = selectedNode.props || {};
        const keyPath = keys.split('.') || [];
        const key = keyPath.pop();
        let finalProps = keyPath.reduce((a, c) => {
            if (typeof a[c] !== 'undefined')
                return a[c];
            a[c] = {};
            return a[c];
        }, clonedProps);
        finalProps = Object.assign(Object.assign({}, finalProps), { [key]: value });
        yield (0, effects_1.put)(ACTIONS.updateComponent(Object.assign(Object.assign({}, selectedNode), { props: finalProps })));
    }
}
function* handleConditionBind(actions) {
    const { conditionIds } = actions.payload;
    const { selectedNode } = index_1.store.getState().builder.main;
    if (selectedNode) {
        const { directive = {} } = selectedNode;
        const ifs = conditionIds.map((item) => `{{${(0, utils_1.getConditionRelationKey)(item)}}}`);
        const newDirective = Object.assign(Object.assign({}, directive), { if: ifs });
        yield (0, effects_1.put)(ACTIONS.updateComponent(Object.assign(Object.assign({}, selectedNode), { directive: newDirective })));
    }
}
function* watch() {
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.dropComponent), handleDropComponent);
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.copyComponent), handleCopyComponent);
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.removeComponent), handleRemoveComponent);
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.updateComponent), handleUpdateComponent);
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.afterUpdateComponent), handleAfterUpdate);
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.variableBind), handleVariableBind);
    yield (0, effects_1.takeLatest)((0, typesafe_actions_1.getType)(ACTIONS.conditionBind), handleConditionBind);
}
function* rootSaga() {
    yield (0, effects_1.all)([watch()]);
}
exports.default = rootSaga;
