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

export type Series = {
  id: string;
  name: string;
  description: string;
  type: "series";
  tags: string[];
  meta: {
    date: Date;
    image: string;
    author: string;
    tmdbId?: number;
    rating: number;
    average?: string;
    thumbnail?: string;
    done?: boolean;
  };
};

function renderSeries(series: Series) {
  const meta = series.meta;
  if ("date" in meta) {
    meta.date = formatDate(meta.date);
  }

  delete meta.thumbnail;
  delete meta.average;

  const movieImage = `![](${series.meta.image})`;

  return fixRenderedMarkdown(`${
    meta
      ? `---
${stringify(meta)}
---`
      : `---
---`
  }
# ${series.name}
${
    // So we do not add a new image to the description everytime we render
    (series.meta.image && !series.description.includes(movieImage))
      ? movieImage
      : ""}
${series.tags.map((t) => `#${t}`).join(" ")}
${series.description}
`);
}

export function parseSeries(original: string, id: string): Series {
  const doc = parseDocument(original);

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

  const range = [Infinity, -Infinity];

  for (const child of doc.children) {
    if (child.type === "yaml") {
      try {
        meta = (parse(child.value) || {}) as Series["meta"];
      } catch (_) {
        // ignore here
      }

      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 description = original.slice(range[0], range[1]);
  const tags = extractHashTags(description);
  for (const tag of tags) {
    description = description.replace("#" + tag, "");
  }

  return {
    type: "series",
    id,
    name,
    tags,
    description,
    meta,
  };
}

const crud = createCrud<Series>({
  prefix: "Media/series/",
  parse: parseSeries,
  render: renderSeries,
  hasThumbnails: true,
});

export const getSeries = crud.read;
export const getAllSeries = crud.readAll;
export const createSeries = crud.create;
