import { readdir, readFile, stat } from "node:fs/promises";
import path from "node:path";

import type { Moment } from "moment";
import type { CachedMetadata } from "obsidian";
import { check, isNotVoid } from "typed-assert";

import { createInMemoryFile, type InMemoryFile } from "../../util/fakes";

const { join } = path.posix;

// NOTE: The plugin relies on obsidian-daily-notes-interface to tell it, which
// files are daily notes, so during tests we have to tell it explicitly.
const dailyNoteFileNames = [
  "2025-07-19",
  "2025-07-20",
  "2025-07-28",
  "2025-07-29",
];

const fixturesDirPath = "fixtures";
const dumpPath = join(fixturesDirPath, "metadata-dump", "tasks.json");
const fixtureVaultPath = join(fixturesDirPath, "fixture-vault");

export async function loadMetadataDump(props: {
  loadedFixtures?: string[];
}): Promise<{
  inMemoryFiles: InMemoryFile[];
  inMemoryDailyNotes: { path: string; file: InMemoryFile; date: Moment }[];
  cachedMetadata: Record<string, CachedMetadata>;
}> {
  const { loadedFixtures } = props;

  const allFiles = await readdir(fixtureVaultPath);

  const inMemoryFiles = await Promise.all(
    allFiles
      .filter((file) => (loadedFixtures ? loadedFixtures.includes(file) : true))
      .map(async (file) => {
        const filePath = join(fixtureVaultPath, file);

        const stats = await stat(filePath);

        if (!stats.isFile()) {
          throw new TypeError(
            `Only files are supported in fixture vault, not this: ${filePath}`,
          );
        }

        const contents = await readFile(filePath, "utf8");

        return createInMemoryFile({ path: filePath, contents });
      }),
  );

  const rawMetadataDump = await readFile(dumpPath, "utf-8");

  const metadataDump = JSON.parse(rawMetadataDump);
  const { cachedMetadata } = metadataDump;

  const pathToInMemoryFile = Object.fromEntries(
    inMemoryFiles.map((it) => [it.path, it]),
  );

  const inMemoryDailyNotes = dailyNoteFileNames
    .map((it) => {
      const path = join(fixtureVaultPath, `${it}.md`);
      const file = pathToInMemoryFile[path];

      if (!file) {
        return undefined;
      }

      return { path, file, date: window.moment(it) };
    })
    .filter(check(isNotVoid));

  return {
    inMemoryFiles,
    inMemoryDailyNotes,
    cachedMetadata,
  };
}
