import { DEBUG } from '@glimmer/env';
import { CONSTANT_TAG } from '@glimmer/reference';
import { EMBER_ENGINES_MOUNT_PARAMS } from '@ember/canary-features';
import { generateControllerFactory } from 'ember-routing';
import { RootReference } from '../utils/references';
import AbstractManager from './abstract';
const CAPABILITIES = {
    dynamicLayout: true,
    dynamicTag: false,
    prepareArgs: false,
    createArgs: false,
    attributeHook: false,
    elementHook: false,
    createCaller: true,
    dynamicScope: true,
    updateHook: true,
    createInstance: true,
};
class MountManager extends AbstractManager {
    getDynamicLayout(state, _) {
        let template = state.engine.lookup('template:application');
        let layout = template.asLayout();
        return {
            handle: layout.compile(),
            symbolTable: layout.symbolTable,
        };
    }
    getCapabilities() {
        return CAPABILITIES;
    }
    create(environment, state) {
        if (DEBUG) {
            this._pushEngineToDebugStack(`engine:${state.name}`, environment);
        }
        // TODO
        // mount is a runtime helper, this shouldn't use dynamic layout
        // we should resolve the engine app template in the helper
        // it also should use the owner that looked up the mount helper.
        let engine = environment.owner.buildChildEngineInstance(state.name);
        engine.boot();
        let applicationFactory = engine.factoryFor(`controller:application`);
        let controllerFactory = applicationFactory || generateControllerFactory(engine, 'application');
        let controller;
        let self;
        let bucket;
        let tag;
        if (EMBER_ENGINES_MOUNT_PARAMS) {
            let modelRef = state.modelRef;
            if (modelRef === undefined) {
                controller = controllerFactory.create();
                self = new RootReference(controller);
                tag = CONSTANT_TAG;
                bucket = { engine, controller, self, tag };
            }
            else {
                let model = modelRef.value();
                let modelRev = modelRef.tag.value();
                controller = controllerFactory.create({ model });
                self = new RootReference(controller);
                tag = modelRef.tag;
                bucket = { engine, controller, self, tag, modelRef, modelRev };
            }
        }
        else {
            controller = controllerFactory.create();
            self = new RootReference(controller);
            tag = CONSTANT_TAG;
            bucket = { engine, controller, self, tag };
        }
        return bucket;
    }
    getSelf({ self }) {
        return self;
    }
    getTag(state) {
        return state.tag;
    }
    getDestructor({ engine }) {
        return engine;
    }
    didRenderLayout() {
        if (DEBUG) {
            this.debugStack.pop();
        }
    }
    update(bucket) {
        if (EMBER_ENGINES_MOUNT_PARAMS) {
            let { controller, modelRef, modelRev } = bucket;
            if (!modelRef.tag.validate(modelRev)) {
                let model = modelRef.value();
                bucket.modelRev = modelRef.tag.value();
                controller.set('model', model);
            }
        }
    }
}
const MOUNT_MANAGER = new MountManager();
export class MountDefinition {
    constructor(name, modelRef) {
        this.manager = MOUNT_MANAGER;
        this.state = { name, modelRef };
    }
}