import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import { AppCmd, } from './app-types.mjs';
import { validateCommonAppData } from './app-helper.mjs';
import { argy_, isArg, isCommand, resulty_ } from '../witness-helper.mjs';
import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
import { getErrorIbGib } from '../../common/error/error-helper.mjs';
import { isComment } from '../../common/comment/comment-helper.mjs';
import { isPic } from '../../common/pic/pic-helper.mjs';
import { WitnessWithContextBase_V1 } from '../witness-with-context/witness-with-context-base-v1.mjs';
const logalot = GLOBAL_LOG_A_LOT || false;
/**
 * ## distinguishing characteristics of apps
 *
 * So for example, one of the simplest apps is one which
 * ...
 *
 * ## architecture
 *
 * ...
 */
export class AppBase_V1 extends WitnessWithContextBase_V1 {
    /**
     * Log context for convenience with logging. (Ignore if you don't want to use this.)
     */
    lc = `[${AppBase_V1.name}]`;
    // /**
    //  * Reference to the local ibgibs service, which is one way at getting at the
    //  * local user space.
    //  */
    // metaspace: MetaspaceService | undefined;
    constructor(initialData, initialRel8ns) {
        super(initialData, initialRel8ns);
    }
    /**
     * At this point in time, the arg has already been intrinsically validated,
     * as well as the internal state of this app. so whatever this app's
     * function is, it should be good to go.
     *
     * In the base class, this just returns {@link routeAndDoArg}. If you don't
     * want to route, then override this.
     */
    async witnessImpl(arg) {
        const lc = `${this.lc}[${this.witnessImpl.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            await this.loadNewerSelfIfAvailable();
            let result = undefined;
            if (isArg({ ibGib: arg })) {
                result = await this.routeAndDoArg({ arg });
            }
            else {
                result = await this.doNonArg({ ibGib: arg });
            }
            // if we didn't get a result, try the default.
            if (!result) {
                console.warn(`${lc} result still falsy. doing default handler. (W: aba0de32c3835056447d7de3a2fb0223)`);
                result = await this.doDefault({ ibGib: arg });
            }
            if (!result) {
                console.warn(`${lc} result falsy...Could not produce result? Was doDefault implemented in concrete class? (W: 15e70486bc33922f9388961bab815223)`);
            }
            return result;
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    /**
     * Base routing executes different if incoming is a cmd options arg, i.e.,
     * if the `data.cmd` is truthy (atow). {@link isArg} is expected to be true
     * at this point. If not, logs an error, **but does not throw**, and returns
     * undefined.
     *
     * Default routing checks arg for command, or if not, checks if comment/pic.
     * If neither of those, then returns undefined atow.
     *
     * Override this function to create more advanced custom routing.
     *
     * ## notes
     *
     * In general, an app ibgib acts more like a normal application in that it
     * accepts commands and not requests. Robbots are more geared to requests,
     * handled semantically.
     *
     * @see {@link isArg}
     * @see {@link doCmdArg}
     * @see {@link doDefault}.
     */
    async routeAndDoArg({ arg, }) {
        const lc = `${this.lc}[${this.routeAndDoArg.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            const ibGib = arg;
            if (!isArg({ ibGib })) {
                throw new Error(`ibGib is not an arg (E: f0e36b13acbcdb1123ee72bdb9ee7723)`);
            }
            if (isCommand({ ibGib })) {
                return this.doCmdArg({ arg: arg });
            }
            else {
                return undefined;
            }
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            if (this.data?.catchAllErrors) {
                return (await getErrorIbGib({ rawMsg: extractErrorMsg(error) }));
            }
            else {
                throw error;
            }
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    // #region do cmd args
    /**
     * By default, this routes to {@link doCmdIb}, {@link doCmdGib} & {@link
     * doCmdIbgib}. This is largely to limit scope of responsibility of app to
     * basic functions. But this is not a concrete rule written in stone.
     *
     * You can always override this and route to other commands before calling
     * this with `super.doCmdArg` as a fallback (if you still want to use this
     * function.)
     *
     * Note that this @throws an error if the data.cmd is not recognized. In this
     * implementation, this occurs if it isn't an ib/gib/ibgib _command_.
     */
    doCmdArg({ arg, }) {
        const lc = `${this.lc}[${this.doCmdArg.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            if (!arg.data?.cmd) {
                throw new Error(`invalid cmd arg. arg.data.cmd required. (E: aec4dd5bd967fbf36f9c4fad22210222)`);
            }
            if (arg.data.cmd === AppCmd.ib) {
                return this.doCmdIb({ arg: arg });
            }
            else if (arg.data.cmd === AppCmd.gib) {
                return this.doCmdGib({ arg: arg });
            }
            else if (arg.data.cmd === AppCmd.ibgib) {
                return this.doCmdIbgib({ arg: arg });
            }
            else {
                throw new Error(`unknown arg.data.cmd: ${arg.data.cmd} (E: 721fa6a5166327134f9504c1caa3e422)`);
            }
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    doCmdIb({ arg, }) {
        const lc = `${this.lc}[${this.doCmdIb.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            throw new Error(`not implemented in base class (E: 7298662a2b8f67611d16a8af0e499422)`);
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    doCmdGib({ arg, }) {
        const lc = `${this.lc}[${this.doCmdGib.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            throw new Error(`not implemented in base class (E: b6bf2c788c734051956481be7283d006)`);
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    doCmdIbgib({ arg, }) {
        const lc = `${this.lc}[${this.doCmdIbgib.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            throw new Error(`not implemented in base class (E: 4fee11f05315467abd036cd8555d27db)`);
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    // #endregion do cmd args
    // #region other stubbed do functions (doPic, doComment, doDefault)
    /**
     * Stubbed in base class for convenience. Doesn't have to be implemented.
     */
    doPic({ ibGib, }) {
        const lc = `${this.lc}[${this.doPic.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            throw new Error(`not implemented in base class (E: 16ba889931644d42ad9e476757dd0617)`);
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    /**
     * Stubbed in base class for convenience. Doesn't have to be implemented.
     */
    doComment({ ibGib, }) {
        const lc = `${this.lc}[${this.doComment.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            throw new Error(`not implemented in base class (E: 0486a7864729456d993a1afe246faea4)`);
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    doNonArg({ ibGib, }) {
        const lc = `${this.lc}[${this.doNonArg.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            if (isComment({ ibGib })) {
                return this.doComment({ ibGib: ibGib });
            }
            else if (isPic({ ibGib })) {
                return this.doPic({ ibGib: ibGib });
            }
            else {
                return this.doDefault({ ibGib });
            }
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    /**
     * Stubbed in base class for convenience. Doesn't have to be implemented.
     */
    doDefault({ ibGib, }) {
        const lc = `${this.lc}[${this.doDefault.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            throw new Error(`not implemented in base class (E: 5038662186617aaf1f0cc698fd1f9622)`);
            // return this.doDefaultImpl({ibGib});
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    // #endregion other stubbed do functions (doPic, doComment, doDefault)
    /**
     * validates against common app qualities.
     *
     * Override this with a call to `super.validateThis` for custom validation
     * for descending app classes.
     *
     * @returns validation errors common to all apps, if any errors exist.
     */
    async validateThis() {
        const lc = `${this.lc}[${this.validateThis.name}]`;
        try {
            if (logalot) {
                console.log(`${lc} starting...`);
            }
            if (!this.data) {
            }
            const errors = [
                // ...await super.validateThis(),
                ...validateCommonAppData({ appData: this.data }),
            ];
            return errors;
        }
        catch (error) {
            console.error(`${lc} ${extractErrorMsg(error)}`);
            throw error;
        }
        finally {
            if (logalot) {
                console.log(`${lc} complete.`);
            }
        }
    }
    /**
     * builds an arg ibGib.
     *
     * wrapper convenience to avoid long generic calls.
     */
    async argy({ argData, ibMetadata, noTimestamp, ibGibs, }) {
        const arg = await argy_({
            argData,
            ibMetadata,
            noTimestamp
        });
        if (ibGibs) {
            arg.ibGibs = ibGibs;
        }
        return arg;
    }
    /**
     * builds a result ibGib, if indeed a result ibgib is required.
     *
     * This is only useful in apps that have more structured inputs/outputs.
     * For those that simply accept any ibgib incoming and return a
     * primitive like ib^gib or whatever, then this is unnecessary.
     *
     * wrapper convenience to avoid long generic calls.
     */
    async resulty({ resultData, ibGibs, }) {
        const result = await resulty_({
            // ibMetadata: getAppResultMetadata({space: this}),
            resultData,
        });
        if (ibGibs) {
            result.ibGibs = ibGibs;
        }
        return result;
    }
}
//# sourceMappingURL=app-base-v1.mjs.map