import { RenderPlugin, IdAttributePlugin } from "@11ty/eleventy";
import eleventyNavigationPlugin from "@11ty/eleventy-navigation";
import { feedPlugin } from "@11ty/eleventy-plugin-rss";

import markdownIt from "markdown-it";
import markdownItFootnote from "markdown-it-footnote";

import { DateTime } from "luxon";
import { chunk } from "lodash-es";

export default function (eleventyConfig) {
  const MARKDOWN_OPTIONS = {
    html: true,
    breaks: true,
    linkify: true,
    typographer: true,
  };

  let md = markdownIt(MARKDOWN_OPTIONS).use(markdownItFootnote);

  // Libraries
  eleventyConfig.setLibrary("md", md);

  // Plugins
  eleventyConfig.addPlugin(RenderPlugin);
  eleventyConfig.addPlugin(IdAttributePlugin);
  eleventyConfig.addPlugin(eleventyNavigationPlugin);
  eleventyConfig.addPlugin(feedPlugin, {
    type: "atom", // or "rss", "json"
    outputPath: "/feed.xml",
    collection: {
      name: "post", // iterate over `collections.posts`
      limit: 10, // 0 means no limit
    },
    metadata: {
      language: "en",
      title: "Gil•INK",
      subtitle: "Gil's personal website",
      base: "https://gil.ink/",
      author: {
        name: "Gil C.",
        email: "hello@gil.ink",
      },
    },
  });

  // Filters
  eleventyConfig.addFilter("filterByCategory", function (posts, cat) {
    /*
	  case matters, so let's lowercase the desired category, cat
	  and we will lowercase our posts categories
	  */
    cat = cat.toLowerCase();
    let result = posts.filter((p) => {
      let cats = p.data.categories.map((s) => s.toLowerCase());
      return cats.includes(cat);
    });
    return result;
  });

  eleventyConfig.addFilter("formatDate", function (date, format) {
    return DateTime.fromJSDate(date).toFormat(format);
  });

  eleventyConfig.addFilter("formatDateIso", function (date, format) {
    return DateTime.fromISO(date).toFormat(format);
  });

  eleventyConfig.addFilter("formatDateRel", function (date) {
    return DateTime.fromJSDate(date).toRelative();
  });

  eleventyConfig.addFilter("formatDateIsoRel", function (date) {
    return DateTime.fromISO(date).toRelative();
  });

  eleventyConfig.addFilter("md", function (content = "") {
    return md.render(content);
  });

  eleventyConfig.addFilter("mdInline", function (content = "") {
    return md.renderInline(content);
  });

  // Passthrough copies
  ["src/assets"].forEach((path) => {
    eleventyConfig.addPassthroughCopy(path);
  });

  // Watch targets
  eleventyConfig.addWatchTarget("./src/assets/css");

  // Frontmatter parsing
  eleventyConfig.setFrontMatterParsingOptions({ excerpt: true });

  // COLLECTIONS
  ////// Categories
  eleventyConfig.addCollection("categories", function (collectionApi) {
    let categories = new Set();
    let posts = collectionApi.getFilteredByTag("post");
    posts.forEach((p) => {
      let cats = p.data.categories;
      cats.forEach((c) => categories.add(c));
    });

    return Array.from(categories);
  });

  ////// Paginated tags (by @zachleat)
  // See: https://github.com/11ty/eleventy/issues/332#issuecomment-445236776
  // note that this uses the lodash.chunk method, so you’ll have to require that
  eleventyConfig.addCollection("tagPagination", function (collectionApi) {
    // Get unique list of tags
    let tagSet = new Set();
    collectionApi.getAllSorted().map(function (item) {
      if ("tags" in item.data) {
        let tags = item.data.tags;

        // optionally filter things out before you iterate over?
        for (let tag of tags) {
          tagSet.add(tag);
        }
      }
    });

    // Get each item that matches the tag
    let paginationSize = 10;
    let tagMap = [];
    let tagArray = [...tagSet];
    for (let tagName of tagArray) {
      let tagItems = collectionApi.getFilteredByTag(tagName);
      let pagedItems = chunk(tagItems, paginationSize);
      //console.log( tagName, tagItems.length, pagedItems.length );
      for (
        let pageNumber = 0, max = pagedItems.length;
        pageNumber < max;
        pageNumber++
      ) {
        tagMap.push({
          tagName: tagName,
          pageNumber: pageNumber,
          pageSize: pagedItems.length,
          pageData: pagedItems[pageNumber],
        });
      }
    }

    /* return data looks like:
      [{
        tagName: "tag1",
        pageNumber: 0
        pageData: [] // array of items
      },{
        tagName: "tag1",
        pageNumber: 1
        pageData: [] // array of items
      },{
        tagName: "tag1",
        pageNumber: 2
        pageData: [] // array of items
      },{
        tagName: "tag2",
        pageNumber: 0
        pageData: [] // array of items
      }]
	  */
    //console.log( tagMap );
    return tagMap;
  });

  ////// Paginated categories (by @zachleat)
  eleventyConfig.addCollection("catPagination", function (collectionApi) {
    // Get unique list of tags
    let catSet = new Set();
    collectionApi.getAllSorted().map(function (item) {
      if ("categories" in item.data) {
        let cats = item.data.categories;

        // optionally filter things out before you iterate over?
        for (let cat of cats) {
          catSet.add(cat);
        }
      }
    });

    // Get each item that matches the tag
    let paginationSize = 10;
    let catMap = [];
    let catArray = [...catSet];
    for (let catName of catArray) {
      let catItems = collectionApi.getAllSorted().filter(function (item) {
        if ("categories" in item.data) {
          return item.data.categories.includes(catName);
        } else {
          return false;
        }
      });
      let pagedItems = chunk(catItems, paginationSize);
      //console.log( tagName, tagItems.length, pagedItems.length );
      for (
        let pageNumber = 0, max = pagedItems.length;
        pageNumber < max;
        pageNumber++
      ) {
        catMap.push({
          catName: catName,
          pageNumber: pageNumber,
          pageSize: pagedItems.length,
          pageData: pagedItems[pageNumber],
        });
      }
    }

    /* return data looks like:
      [{
        tagName: "tag1",
        pageNumber: 0
        pageData: [] // array of items
      },{
        tagName: "tag1",
        pageNumber: 1
        pageData: [] // array of items
      },{
        tagName: "tag1",
        pageNumber: 2
        pageData: [] // array of items
      },{
        tagName: "tag2",
        pageNumber: 0
        pageData: [] // array of items
      }]
	  */
    //console.log( tagMap );
    return catMap;
  });

  return {
    dir: {
      input: "src",
      includes: "_components",
      layouts: "_layouts",
    },
  };
}
