const path = require(`path`)
const _ = require('lodash')
const { createFilePath } = require(`gatsby-source-filesystem`)

const recentPosts = []
const archives = {}
const tagsFrequent = []

const feedRecentPosts = []
const feedArchives = {}
const feedTagsFrequent = []

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions

  // Define a template for blog post
  const blogPostTemplate = path.resolve(`./src/templates/blog-post.tsx`)
  const blogListTemplate = path.resolve(`./src/templates/blog-list.tsx`)
  const blogSearchTemplate = path.resolve(`./src/templates/blog-search.tsx`)

  // Define a template for feed post
  const feedPostTemplate = path.resolve(`./src/templates/feed-post.tsx`)
  const feedListTemplate = path.resolve(`./src/templates/feed-list.tsx`)

  // Get all markdown blog posts sorted by date
  const result = await graphql(
    `
      {
        allMarkdownRemark(
          sort: { frontmatter: { date: DESC } }
          limit: 1000
          filter: { fileAbsolutePath: { regex: "/content/blog/" } }
        ) {
          nodes {
            id
            fields {
              slug
            }
            frontmatter {
              title
              date(formatString: "YYYY")
            }
          }
        }
        tagsGroup: allMarkdownRemark(
          limit: 1000
          filter: { fileAbsolutePath: { regex: "/content/blog/" } }
        ) {
          group(field: { frontmatter: { tags: SELECT } }) {
            name: fieldValue
            totalCount
          }
        }
      }
    `
  )

  if (result.errors) {
    reporter.panicOnBuild(
      `There was an error loading your blog posts`,
      result.errors
    )
    return
  }

  const posts = result.data.allMarkdownRemark.nodes
  recentPosts.push(
    ...posts.slice(0, 10).map((p) => ({
      slug: p.fields.slug,
      title: p.frontmatter.title
    }))
  )

  const tags = result.data.tagsGroup.group
  tagsFrequent.push(
    ...tags.sort((a, b) => b.totalCount - a.totalCount).slice(0, 10)
  )

  // side bar data for each page
  posts.forEach((d) => {
    if (archives[d.frontmatter.date] == null) archives[d.frontmatter.date] = 0
    archives[d.frontmatter.date]++
  })

  // Create blog posts pages
  // But only if there's at least one markdown file found at "content/blog" (defined in gatsby-config.js)
  // `context` is available in the template as a prop and as a variable in GraphQL

  if (posts.length > 0) {
    posts.forEach((post, index) => {
      const previousPostId = index === 0 ? null : posts[index - 1].id
      const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id

      createPage({
        path: post.fields.slug,
        component: blogPostTemplate,
        context: {
          id: post.id,
          archives,
          recentPosts,
          tags: tagsFrequent,
          previousPostId,
          nextPostId
        }
      })
    })
  }

  // Create blog-list pages
  const postsPerPage = 6
  const numPages = Math.ceil(posts.length / postsPerPage)
  Array.from({ length: numPages }).forEach((_, i) => {
    createPage({
      path: i === 0 ? `/blog` : `/blog/page/${i + 1}`,
      component: blogListTemplate,
      context: {
        page: 'index',
        archives,
        recentPosts,
        tags: tagsFrequent,
        filter: { fileAbsolutePath: { regex: '/content/blog/' } },
        limit: postsPerPage,
        skip: i * postsPerPage,
        numPages: numPages,
        currentPage: i + 1
      }
    })
  })

  for (year in archives) {
    const count = archives[year]
    const numPagesOfYear = Math.ceil(count / postsPerPage)
    Array.from({ length: numPagesOfYear }).forEach((_, i) => {
      createPage({
        path: i === 0 ? `/${year}/` : `/${year}/page/${i + 1}`,
        component: blogListTemplate,
        context: {
          page: 'year',
          archives,
          recentPosts,
          tags: tagsFrequent,
          filter: {
            frontmatter: { date: { gte: year, lt: year + 1 } },
            fileAbsolutePath: { regex: '/content/blog/' }
          },
          limit: postsPerPage,
          skip: i * postsPerPage,
          numPages: numPagesOfYear,
          currentPage: i + 1,
          year: year
        }
      })
    })
  }

  tags.forEach((tag) => {
    const count = tag.totalCount
    const numPagesOfTag = Math.ceil(count / postsPerPage)
    Array.from({ length: numPagesOfTag }).forEach((__, i) => {
      const tagPath = `/category/${_.kebabCase(tag.name)}/`
      createPage({
        path: i === 0 ? tagPath : `${tagPath}page/${i + 1}`,
        component: blogListTemplate,
        context: {
          page: 'category',
          archives,
          recentPosts,
          tags: tagsFrequent,
          filter: { frontmatter: { tags: { in: [tag.name] } } },
          limit: postsPerPage,
          skip: i * postsPerPage,
          numPages: numPagesOfTag,
          currentPage: i + 1,
          tag: tag.name
        }
      })
    })
  })

  createPage({
    path: '/search/',
    component: blogSearchTemplate,
    context: {
      page: 'search',
      archives,
      recentPosts,
      tags: tagsFrequent
    }
  })

  // ---------------------------------------------------------------------
  // Feed section (announcements / social updates) - mirrors the blog logic
  // above but is scoped to /content/feed/ and lives under the /feed/ path
  // ---------------------------------------------------------------------

  const feedResult = await graphql(
    `
      {
        allMarkdownRemark(
          sort: { frontmatter: { date: DESC } }
          limit: 1000
          filter: { fileAbsolutePath: { regex: "/content/feed/" } }
        ) {
          nodes {
            id
            fields {
              slug
            }
            frontmatter {
              title
              date(formatString: "YYYY")
            }
          }
        }
        tagsGroup: allMarkdownRemark(
          limit: 1000
          filter: { fileAbsolutePath: { regex: "/content/feed/" } }
        ) {
          group(field: { frontmatter: { tags: SELECT } }) {
            name: fieldValue
            totalCount
          }
        }
      }
    `
  )

  if (feedResult.errors) {
    reporter.panicOnBuild(
      `There was an error loading your feed posts`,
      feedResult.errors
    )
    return
  }

  const feedPosts = feedResult.data.allMarkdownRemark.nodes
  feedRecentPosts.push(
    ...feedPosts.slice(0, 10).map((p) => ({
      slug: p.fields.slug,
      title: p.frontmatter.title
    }))
  )

  const feedTags = feedResult.data.tagsGroup.group
  feedTagsFrequent.push(
    ...feedTags.sort((a, b) => b.totalCount - a.totalCount).slice(0, 10)
  )

  feedPosts.forEach((d) => {
    if (feedArchives[d.frontmatter.date] == null)
      feedArchives[d.frontmatter.date] = 0
    feedArchives[d.frontmatter.date]++
  })

  // Create individual feed post pages
  if (feedPosts.length > 0) {
    feedPosts.forEach((post, index) => {
      const previousPostId = index === 0 ? null : feedPosts[index - 1].id
      const nextPostId =
        index === feedPosts.length - 1 ? null : feedPosts[index + 1].id

      createPage({
        path: post.fields.slug,
        component: feedPostTemplate,
        context: {
          id: post.id,
          archives: feedArchives,
          recentPosts: feedRecentPosts,
          tags: feedTagsFrequent,
          previousPostId,
          nextPostId
        }
      })
    })
  }

  // Create feed-list pages
  const feedNumPages = Math.ceil(feedPosts.length / postsPerPage)
  Array.from({ length: feedNumPages }).forEach((_, i) => {
    createPage({
      path: i === 0 ? `/feed` : `/feed/page/${i + 1}`,
      component: feedListTemplate,
      context: {
        page: 'index',
        archives: feedArchives,
        recentPosts: feedRecentPosts,
        tags: feedTagsFrequent,
        filter: { fileAbsolutePath: { regex: '/content/feed/' } },
        limit: postsPerPage,
        skip: i * postsPerPage,
        numPages: feedNumPages,
        currentPage: i + 1
      }
    })
  })

  for (year in feedArchives) {
    const count = feedArchives[year]
    const numPagesOfYear = Math.ceil(count / postsPerPage)
    Array.from({ length: numPagesOfYear }).forEach((_, i) => {
      createPage({
        path:
          i === 0 ? `/feed/${year}/` : `/feed/${year}/page/${i + 1}`,
        component: feedListTemplate,
        context: {
          page: 'year',
          archives: feedArchives,
          recentPosts: feedRecentPosts,
          tags: feedTagsFrequent,
          filter: {
            frontmatter: { date: { gte: year, lt: year + 1 } },
            fileAbsolutePath: { regex: '/content/feed/' }
          },
          limit: postsPerPage,
          skip: i * postsPerPage,
          numPages: numPagesOfYear,
          currentPage: i + 1,
          year: year
        }
      })
    })
  }

  feedTags.forEach((tag) => {
    const count = tag.totalCount
    const numPagesOfTag = Math.ceil(count / postsPerPage)
    Array.from({ length: numPagesOfTag }).forEach((__, i) => {
      const tagPath = `/feed/category/${_.kebabCase(tag.name)}/`
      createPage({
        path: i === 0 ? tagPath : `${tagPath}page/${i + 1}`,
        component: feedListTemplate,
        context: {
          page: 'category',
          archives: feedArchives,
          recentPosts: feedRecentPosts,
          tags: feedTagsFrequent,
          filter: {
            frontmatter: { tags: { in: [tag.name] } },
            fileAbsolutePath: { regex: '/content/feed/' }
          },
          limit: postsPerPage,
          skip: i * postsPerPage,
          numPages: numPagesOfTag,
          currentPage: i + 1,
          tag: tag.name
        }
      })
    })
  })
}

exports.onCreatePage = ({ page, actions }) => {
  const { createPage, deletePage } = actions

  if (page.path == '/404/') {
    deletePage(page)
    createPage({
      ...page,
      context: {
        ...page.context,
        archives,
        recentPosts,
        tags: tagsFrequent
      }
    })
  }
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode })

    createNodeField({
      name: `slug`,
      node,
      value
    })
  }
}

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions

  // Explicitly define the siteMetadata {} object
  // This way those will always be defined even if removed from gatsby-config.js

  // Also explicitly define the Markdown frontmatter
  // This way the "MarkdownRemark" queries will return `null` even when no
  // blog posts are stored inside "content/blog" instead of returning an error
  createTypes(`
    type SiteSiteMetadata {
      author: Author
      siteUrl: String
      social: Social
    }

    type Author {
      name: String
      summary: String
    }

    type Social {
      twitter: String
    }

    type MarkdownRemark implements Node {
      frontmatter: Frontmatter
      fields: Fields
    }

    type Frontmatter {
      title: String
      date: Date @dateformat
      author: String
      authorLink: String
      previewImg: File @fileByRelativePath
      tags: [String!]!
    }

    type Fields {
      slug: String
    }
  `)
}
