"use strict";
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAllRoutes = createAllRoutes;
exports.buildAllRoutes = buildAllRoutes;
const tslib_1 = require("tslib");
const lodash_1 = tslib_1.__importDefault(require("lodash"));
const utils_1 = require("@docusaurus/utils");
const blogUtils_1 = require("./blogUtils");
const props_1 = require("./props");
const authors_1 = require("./authors");
async function createAllRoutes(param) {
    const routes = await buildAllRoutes(param);
    routes.forEach(param.actions.addRoute);
}
async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSource, }) {
    const { blogListComponent, blogPostComponent, blogTagsListComponent, blogAuthorsListComponent, blogAuthorsPostsComponent, blogTagsPostsComponent, blogArchiveComponent, routeBasePath, archiveBasePath, authorsBasePath, postsPerPage, pageBasePath, } = options;
    const pluginId = options.id;
    const { createData } = actions;
    const { blogTitle, blogDescription, blogSidebarTitle, blogPosts, blogTags, blogTagsListPath, authorsMap, } = content;
    const blogBasePath = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
    const authorsListPath = (0, utils_1.normalizeUrl)([blogBasePath, authorsBasePath]);
    const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
    const blogPostsById = lodash_1.default.keyBy(blogPosts, (post) => post.id);
    function getBlogPostById(id) {
        const blogPost = blogPostsById[id];
        if (!blogPost) {
            throw new Error(`unexpected, can't find blog post id=${id}`);
        }
        return blogPost;
    }
    const sidebarBlogPosts = options.blogSidebarCount === 'ALL'
        ? blogPosts
        : blogPosts.slice(0, options.blogSidebarCount);
    async function createSidebarModule() {
        const sidebarProp = (0, props_1.toBlogSidebarProp)({
            blogSidebarTitle,
            blogPosts: sidebarBlogPosts,
        });
        const modulePath = await createData(`blog-post-list-prop-${pluginId}.json`, sidebarProp);
        return aliasedSource(modulePath);
    }
    async function createBlogMetadataModule() {
        const blogMetadata = {
            blogBasePath,
            blogTitle,
            authorsListPath,
        };
        const modulePath = await createData(`blogMetadata-${pluginId}.json`, blogMetadata);
        return aliasedSource(modulePath);
    }
    // TODO we should have a parent blog route,
    //  and inject blog metadata + sidebar as a parent context
    //  unfortunately we can't have a parent route for blog yet
    //  because if both blog/docs are using routeBasePath /,
    //  React router config rendering doesn't support that well
    const sidebarModulePath = await createSidebarModule();
    const blogMetadataModulePath = await createBlogMetadataModule();
    function blogPostItemsModule(ids) {
        return ids.map((id) => {
            return {
                content: {
                    __import: true,
                    path: getBlogPostById(id).metadata.source,
                    query: {
                        truncated: true,
                    },
                },
            };
        });
    }
    function createArchiveRoute() {
        if (archiveBasePath && listedBlogPosts.length) {
            return [
                {
                    path: (0, utils_1.normalizeUrl)([blogBasePath, archiveBasePath]),
                    component: blogArchiveComponent,
                    exact: true,
                    props: {
                        archive: { blogPosts: listedBlogPosts },
                    },
                },
            ];
        }
        return [];
    }
    function createBlogPostRouteMetadata(blogPostMeta) {
        return {
            sourceFilePath: (0, utils_1.aliasedSitePathToRelativePath)(blogPostMeta.source),
            lastUpdatedAt: blogPostMeta.lastUpdatedAt,
        };
    }
    await Promise.all(blogPosts.map(async (blogPost) => {
        const { metadata } = blogPost;
        await createData(
        // Note that this created data path must be in sync with
        // metadataPath provided to mdx-loader.
        `${(0, utils_1.docuHash)(metadata.source)}.json`, metadata);
    }));
    function createBlogPostRoute(blogPost) {
        return {
            path: blogPost.metadata.permalink,
            component: blogPostComponent,
            exact: true,
            modules: {
                sidebar: sidebarModulePath,
                content: blogPost.metadata.source,
            },
            metadata: createBlogPostRouteMetadata(blogPost.metadata),
            context: {
                blogMetadata: blogMetadataModulePath,
            },
        };
    }
    function createBlogPostRoutes() {
        return blogPosts.map(createBlogPostRoute);
    }
    function createBlogPostsPaginatedRoutes() {
        const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
            blogPosts: listedBlogPosts,
            blogTitle,
            blogDescription,
            postsPerPageOption: postsPerPage,
            basePageUrl: blogBasePath,
            pageBasePath,
        });
        return blogListPaginated.map((paginated) => {
            return {
                path: paginated.metadata.permalink,
                component: blogListComponent,
                exact: true,
                modules: {
                    sidebar: sidebarModulePath,
                    items: blogPostItemsModule(paginated.items),
                },
                props: {
                    metadata: paginated.metadata,
                },
            };
        });
    }
    function createTagsRoutes() {
        // Tags. This is the last part so we early-return if there are no tags.
        if (Object.keys(blogTags).length === 0) {
            return [];
        }
        const tagsListRoute = {
            path: blogTagsListPath,
            component: blogTagsListComponent,
            exact: true,
            modules: {
                sidebar: sidebarModulePath,
            },
            props: {
                tags: (0, props_1.toTagsProp)({ blogTags }),
            },
        };
        function createTagPaginatedRoutes(tag) {
            return tag.pages.map((paginated) => {
                return {
                    path: paginated.metadata.permalink,
                    component: blogTagsPostsComponent,
                    exact: true,
                    modules: {
                        sidebar: sidebarModulePath,
                        items: blogPostItemsModule(paginated.items),
                    },
                    props: {
                        tag: (0, props_1.toTagProp)({ tag, blogTagsListPath }),
                        listMetadata: paginated.metadata,
                    },
                };
            });
        }
        const tagsPaginatedRoutes = Object.values(blogTags).flatMap(createTagPaginatedRoutes);
        return [tagsListRoute, ...tagsPaginatedRoutes];
    }
    function createAuthorsRoutes() {
        if (authorsMap === undefined || Object.keys(authorsMap).length === 0) {
            return [];
        }
        const blogPostsByAuthorKey = (0, authors_1.groupBlogPostsByAuthorKey)({
            authorsMap,
            blogPosts,
        });
        const authors = Object.values(authorsMap);
        return [
            createAuthorListRoute(),
            ...authors.flatMap(createAuthorPaginatedRoute),
        ];
        function createAuthorListRoute() {
            return {
                path: authorsListPath,
                component: blogAuthorsListComponent,
                exact: true,
                modules: {
                    sidebar: sidebarModulePath,
                },
                props: {
                    authors: authors.map((author) => {
                        const authorPosts = blogPostsByAuthorKey[author.key] ?? [];
                        const listedAuthorPosts = authorPosts.filter(blogUtils_1.shouldBeListed);
                        return (0, props_1.toAuthorItemProp)({
                            author,
                            count: listedAuthorPosts.length,
                        });
                    }),
                },
                context: {
                    blogMetadata: blogMetadataModulePath,
                },
            };
        }
        function createAuthorPaginatedRoute(author) {
            const authorBlogPosts = blogPostsByAuthorKey[author.key] ?? [];
            const listedAuthorBlogPosts = authorBlogPosts.filter(blogUtils_1.shouldBeListed);
            if (!author.page) {
                return [];
            }
            const pages = (0, blogUtils_1.paginateBlogPosts)({
                blogPosts: listedAuthorBlogPosts,
                basePageUrl: author.page.permalink,
                blogDescription,
                blogTitle,
                pageBasePath,
                postsPerPageOption: postsPerPage,
            });
            return pages.map(({ metadata, items }) => {
                return {
                    path: metadata.permalink,
                    component: blogAuthorsPostsComponent,
                    exact: true,
                    modules: {
                        items: blogPostItemsModule(items),
                        sidebar: sidebarModulePath,
                    },
                    props: {
                        author: (0, props_1.toAuthorItemProp)({
                            author,
                            count: listedAuthorBlogPosts.length,
                        }),
                        listMetadata: metadata,
                    },
                    context: {
                        blogMetadata: blogMetadataModulePath,
                    },
                };
            });
        }
    }
    return [
        ...createBlogPostRoutes(),
        ...createBlogPostsPaginatedRoutes(),
        ...createTagsRoutes(),
        ...createArchiveRoute(),
        ...createAuthorsRoutes(),
    ];
}
