import { parseDocument } from "@lib/documents.ts";
import { parse } from "yaml";
import { createCrud } from "@lib/crud.ts";
import { stringify } from "$std/yaml/stringify.ts";
import { extractHashTags, formatDate } from "@lib/string.ts";
import { fixRenderedMarkdown } from "@lib/helpers.ts";
import { getThumbhash } from "@lib/cache/image.ts";

export type Article = {
  id: string;
  type: "article";
  content: string;
  name: string;
  tags: string[];
  meta: {
    done?: boolean;
    date: Date;
    link: string;
    thumbnail?: string;
    average?: string;
    image?: string;
    author?: string;
    rating?: number;
  };
};

function renderArticle(article: Article) {
  const meta = article.meta;
  if ("date" in meta) {
    meta.date = formatDate(meta.date);
  }

  return fixRenderedMarkdown(`${
    meta
      ? `---
${stringify(meta)}
---`
      : `---
---`
  }
# ${article.name}
${article.tags.map((t) => `#${t}`).join(" ")}
${article.content}
`);
}

function parseArticle(original: string, id: string): Article {
  const doc = parseDocument(original);

  let meta = {} as Article["meta"];
  let name = "";

  const range = [Infinity, -Infinity];

  for (const child of doc.children) {
    if (child.type === "yaml") {
      meta = parse(child.value) as Article["meta"];

      if (meta["rating"] && typeof meta["rating"] === "string") {
        meta.rating = [...meta.rating?.matchAll("⭐")].length;
      }

      continue;
    }

    if (
      child.type === "heading" && child.depth === 1 && !name &&
      child.children.length === 1 && child.children[0].type === "text"
    ) {
      name = child.children[0].value;
      continue;
    }

    if (name) {
      const start = child.position?.start.offset || Infinity;
      const end = child.position?.end.offset || -Infinity;
      if (start < range[0]) range[0] = start;
      if (end > range[1]) range[1] = end;
    }
  }

  let content = original.slice(range[0], range[1]);
  const tags = extractHashTags(content);
  for (const tag of tags) {
    content = content.replace("#" + tag, "");
  }

  return {
    type: "article",
    id,
    name,
    tags,
    content,
    meta,
  };
}

const crud = createCrud<Article>({
  prefix: "Media/articles/",
  parse: parseArticle,
  render: renderArticle,
  hasThumbnails: true,
});
export const getAllArticles = crud.readAll;
export const getArticle = crud.read;
export const createArticle = crud.create;
