import fs from "fs/promises";
import path from "path";

import matter from "gray-matter";
import { MDXRemoteSerializeResult } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";

const EVENTS_PATH = path.join("content", "events");
const TERMS = ["winter", "spring", "fall"];

export async function getEventYears(): Promise<string[]> {
  return (await fs.readdir(EVENTS_PATH, { withFileTypes: true }))
    .filter((dirent) => dirent.isDirectory())
    .map((dirent) => dirent.name)
    .sort();
}

export async function getEventTermsByYear(year: string): Promise<string[]> {
  return (
    await fs.readdir(path.join(EVENTS_PATH, year), { withFileTypes: true })
  )
    .filter((dirent) => dirent.isDirectory() && TERMS.includes(dirent.name))
    .map((dirent) => dirent.name)
    .sort((a, b) => TERMS.indexOf(a) - TERMS.indexOf(b));
}

interface Metadata {
  name: string;
  short: string;
  date: string;
  online: boolean;
  location: string;
}

export interface Event {
  content: MDXRemoteSerializeResult<Record<string, unknown>>;
  metadata: Metadata;
}

export async function getEventBySlug(
  year: string,
  term: string,
  slug: string
): Promise<Event> {
  const raw = await fs.readFile(
    path.join(EVENTS_PATH, year, term, `${slug}.md`),
    "utf-8"
  );
  const { content, data: metadata } = matter(raw);

  return {
    content: await serialize(content),
    metadata: metadata as Metadata,
  };
}

export async function getEventsByTerm(
  year: string,
  term: string
): Promise<string[]> {
  return (await fs.readdir(path.join(EVENTS_PATH, year, term)))
    .filter((name) => name.endsWith(".md"))
    .map((name) => name.slice(0, -".md".length));
}

export async function getUpcomingEvents(): Promise<Event[]> {
  const today = new Date();
  const currentYear = today.getFullYear();
  const currentTerm = Math.trunc(today.getMonth() / 4);
  const nextYear = currentTerm < 2 ? currentYear : currentYear + 1;
  const nextTerm = (currentTerm + 1) % 3;

  const events: Event[] = (
    await Promise.all(
      [
        { year: currentYear.toString(), term: currentTerm },
        { year: nextYear.toString(), term: nextTerm },
      ].map(async ({ year, term }) => {
        try {
          const eventsInTerm = await getEventsByTerm(year, TERMS[term]);
          return await Promise.all(
            eventsInTerm.map((slug) => getEventBySlug(year, TERMS[term], slug))
          );
        } catch (error) {
          return [];
        }
      })
    )
  ).flat();

  return events
    .filter((ev) => new Date(ev.metadata.date).getTime() >= Date.now())
    .sort((a, b) => {
      return (
        new Date(a.metadata.date).getTime() -
        new Date(b.metadata.date).getTime()
      );
    });
}
