import { createDefaultMetadata } from "./default-metadata";
import { resolveOpenGraph, resolveTwitter } from "./resolvers/resolve-opengraph";
import { mergeTitle } from "./resolvers/resolve-title";
import { resolveAsArrayOrUndefined } from "./generate/utils";
import { isClientReference } from "../../build/is-client-reference";
import { getLayoutOrPageModule } from "../../server/lib/app-dir-module";
import { interopDefault } from "../interop-default";
import { resolveAlternates, resolveAppleWebApp, resolveAppLinks, resolveRobots, resolveVerification, resolveViewport } from "./resolvers/resolve-basics";
import { resolveIcons } from "./resolvers/resolve-icons";
// Merge the source metadata into the resolved target metadata.
function merge(target, source, templateStrings) {
    const metadataBase = source.metadataBase || null;
    for(const key_ in source){
        const key = key_;
        switch(key){
            case "title":
                {
                    if (source.title) {
                        target.title = source.title;
                        mergeTitle(target, templateStrings.title);
                    }
                    break;
                }
            case "alternates":
                {
                    target.alternates = resolveAlternates(source.alternates, metadataBase);
                    break;
                }
            case "openGraph":
                {
                    target.openGraph = resolveOpenGraph(source.openGraph, metadataBase);
                    if (target.openGraph) {
                        mergeTitle(target.openGraph, templateStrings.openGraph);
                    }
                    break;
                }
            case "twitter":
                {
                    target.twitter = resolveTwitter(source.twitter, metadataBase);
                    if (target.twitter) {
                        mergeTitle(target.twitter, templateStrings.twitter);
                    }
                    break;
                }
            case "verification":
                target.verification = resolveVerification(source.verification);
                break;
            case "viewport":
                {
                    target.viewport = resolveViewport(source.viewport);
                    break;
                }
            case "icons":
                {
                    target.icons = resolveIcons(source.icons);
                    break;
                }
            case "appleWebApp":
                target.appleWebApp = resolveAppleWebApp(source.appleWebApp);
                break;
            case "appLinks":
                target.appLinks = resolveAppLinks(source.appLinks);
                break;
            case "robots":
                {
                    target.robots = resolveRobots(source.robots);
                    break;
                }
            case "archives":
            case "assets":
            case "bookmarks":
            case "keywords":
            case "authors":
                {
                    // FIXME: type inferring
                    // @ts-ignore
                    target[key] = resolveAsArrayOrUndefined(source[key]) || null;
                    break;
                }
            // directly assign fields that fallback to null
            case "applicationName":
            case "description":
            case "generator":
            case "themeColor":
            case "creator":
            case "publisher":
            case "category":
            case "classification":
            case "referrer":
            case "colorScheme":
            case "itunes":
            case "formatDetection":
                // @ts-ignore TODO: support inferring
                target[key] = source[key] || null;
                break;
            case "other":
                target.other = Object.assign({}, target.other, source.other);
                break;
            case "metadataBase":
                target.metadataBase = metadataBase;
                break;
            default:
                break;
        }
    }
}
async function getDefinedMetadata(mod, props) {
    // Layer is a client component, we just skip it. It can't have metadata
    // exported. Note that during our SWC transpilation, it should check if
    // the exports are valid and give specific error messages.
    if (isClientReference(mod)) {
        return null;
    }
    if (mod.metadata && mod.generateMetadata) {
        throw new Error(`${mod.path} is exporting both metadata and generateMetadata which is not supported. If all of the metadata you want to associate to this page/layout is static use the metadata export, otherwise use generateMetadata. File: ${mod.path}`);
    }
    return (mod.generateMetadata ? (parent)=>mod.generateMetadata(props, parent) : mod.metadata) || null;
}
async function collectStaticFsBasedIcons(metadata, type) {
    if (!(metadata == null ? void 0 : metadata[type])) return undefined;
    const iconPromises = metadata[type].map(// TODO-APP: share the typing between next-metadata-image-loader and here
    async (iconResolver)=>interopDefault(await iconResolver()));
    return (iconPromises == null ? void 0 : iconPromises.length) > 0 ? await Promise.all(iconPromises) : undefined;
}
async function resolveStaticMetadata(components) {
    const { metadata  } = components;
    if (!metadata) return null;
    const [icon, apple] = await Promise.all([
        collectStaticFsBasedIcons(metadata, "icon"),
        collectStaticFsBasedIcons(metadata, "apple"), 
    ]);
    const icons = {};
    if (icon) icons.icon = icon;
    if (apple) icons.apple = apple;
    return {
        icons
    };
}
// [layout.metadata, static files metadata] -> ... -> [page.metadata, static files metadata]
export async function collectMetadata(loaderTree, props, array) {
    const mod = await getLayoutOrPageModule(loaderTree);
    const staticFilesMetadata = await resolveStaticMetadata(loaderTree[2]);
    const metadataExport = mod ? await getDefinedMetadata(mod, props) : null;
    array.push([
        metadataExport,
        staticFilesMetadata
    ]);
}
export async function accumulateMetadata(metadataItems) {
    const resolvedMetadata = createDefaultMetadata();
    let parentPromise = Promise.resolve(resolvedMetadata);
    for (const item of metadataItems){
        const [metadataExport, staticFilesMetadata] = item;
        const layerMetadataPromise = Promise.resolve(typeof metadataExport === "function" ? metadataExport(parentPromise) : metadataExport);
        parentPromise = parentPromise.then((resolved)=>{
            return layerMetadataPromise.then((exportedMetadata)=>{
                const metadata = exportedMetadata || staticFilesMetadata;
                if (metadata) {
                    var ref, ref1, ref2, ref3, ref4;
                    // Overriding the metadata if static files metadata is present
                    merge(resolved, {
                        ...metadata,
                        ...staticFilesMetadata
                    }, {
                        title: ((ref = resolved.title) == null ? void 0 : ref.template) || null,
                        openGraph: ((ref1 = resolved.openGraph) == null ? void 0 : (ref2 = ref1.title) == null ? void 0 : ref2.template) || null,
                        twitter: ((ref3 = resolved.twitter) == null ? void 0 : (ref4 = ref3.title) == null ? void 0 : ref4.template) || null
                    });
                }
                return resolved;
            });
        });
    }
    return await parentPromise;
}

//# sourceMappingURL=resolve-metadata.js.map