/* Essentials YOOtheme Pro 2.3.4 build 0217.0955; ZOOlanders https://www.zoolanders.com; Copyright (C) Joolanders, SL; http://www.gnu.org/licenses/gpl.html GNU/GPL */

import api from '@yootheme/api';
import hooks from '@yootheme/hooks';
import essentials from 'yooessentials';
import { flattenChildren } from '@yooessentials/util';

hooks.after('app.init', () => {
    const { Source } = api.builder.helpers;

    extendSource(Source);
});

function extendSource(Source) {
    // extend getSourcePath
    const getSourcePathFn = Source.getSourcePath.bind(Source);

    Source.getSourcePath = function (nodes, ...args) {
        const globalKey = essentials.helpers.Source.globalKey;

        let path = getSourcePathFn(nodes, ...args);

        if (path?.includes(globalKey)) {
            const id = essentials.helpers.Source.getGobalQueryId(path);
            const globalQuery = essentials.helpers.Dynamic.getGlobalQuery(id);

            if (globalQuery) {
                path = path.replace(`${globalKey}${id}`, globalQuery?.source?.query?.name);
            }
        }

        return path;
    };

    // extend hasSource
    const hasSourceFn = Source.hasSource.bind(Source);

    Source.hasSource = function (node, ...args) {
        const result = hasSourceFn(node, ...args);
        return result || hasPropsWithQuery(node);
    };

    // extend hasInvalidSource
    const hasInvalidSourceFn = Source.hasInvalidSource.bind(Source);

    Source.hasInvalidSource = function (node, ...args) {
        let result = hasInvalidSourceFn(node, ...args);

        // source with no props, could have deep nested props
        if (
            (result === 'empty-props' || !result) &&
            (hasInheritingProps(node) || hasExtendingProps(node))
        ) {
            return false;
        }

        if (hasPropsWithQuery(node)) {
            const props = node?.source_extended?.props || {};

            result = Object.keys(props).some((key) => {
                const prop = props[key];

                if (prop?.composed?.sources) {
                    const sources = prop.composed.sources;
                    return Object.keys(sources).some((key) =>
                        validateSource(node, key, sources[key], ...args)
                    );
                }

                return validateSource(node, key, prop, ...args);
            });
        }

        return result;
    };

    function validateSource(node, key, source, ...args) {
        if (!source?.query?.name) {
            return false;
        }

        if (source.query.name === essentials.helpers.Source.parentKey) {
            return !essentials.helpers.Source.getClosestInheritableNode(node);
        }

        // emulate node to validate query
        const n = {
            type: 'mocked',
            source: {
                props: {
                    [key]: source
                },
                query: source.query
            }
        };

        return hasInvalidSourceFn(n, ...args);
    }

    function hasPropsWithQuery(node) {
        const props = node?.source_extended?.props || {};

        return Object.keys(props).some((key) => {
            return props[key]?.query?.name || props[key]?.composed;
        });
    }

    function hasExtendingProps(node) {
        const props = node?.source_extended?.props || {};

        return Object.keys(props).some((key) => {
            return props[key]?.query?.field?.name;
        });
    }

    function hasInheritingProps(node) {
        const nodes = flattenChildren(node);

        return nodes.some((child) => {
            const props = child?.source_extended?.props || {};

            return Object.keys(props).some((key) => {
                const prop = props[key];

                if (prop?.composed?.sources) {
                    const sources = prop.composed.sources;
                    return Object.keys(sources).some(
                        (key) => sources[key]?.query?.name === essentials.helpers.Source.parentKey
                    );
                }

                return prop?.query?.name === essentials.helpers.Source.parentKey;
            });
        });
    }
}
