import fsPromises from "node:fs/promises";
import { parse as parseYaml } from "yaml";

const LIB_PATH = "../data/";

type AnyObject = {[k: string]: any};

const readText = (path: string): Promise<string> =>
  fsPromises.readFile(path, {encoding: "utf-8"});

const makeReader = (parser: (s: string) => AnyObject) => async (path: string): Promise<AnyObject> => {
  try {
    const text = await readText(path);
    return parser(text);
  } catch (e) {
    return {};
  };
};

const readMetadata = async (basePath: string): Promise<AnyObject> => {
  const fmts = [
    [readYaml, "yaml"],
    [readYaml, "yml"],
    [readJson, "json"],
  ] as const;
  for (const fmt of fmts) {
    const md = await fmt[0](`${basePath}/metadata.${fmt[1]}`);
    if (md && Object.keys(md).length > 0)
      return md;
  };
  return {};
}

const readJson = makeReader(JSON.parse);
const readYaml = makeReader(parseYaml);

const getMetrics = async (path: string): Promise<any> => {
  try {
    const data = await readMetadata(path);
    const metrics = data.metrics ?? {};
    return {
      ...(metrics.analysis ?? {}),
    };
  } catch (e) {
    return {};
  }
};

const readVariantsFromEntry = async (entryPath: string): Promise<Array<any>> => {
  // const entryMd = await readYaml(entryPath + "/metadata.yml");
  const entryMd = await readMetadata(entryPath);
  const variants = entryMd.system?.variants ?? {};
  const variantMds = Object.keys(variants).map(async (v: any) => {
    // const metrics = await getMetrics(`${entryPath}/data/${v}/metadata.json`);
    const metrics = await getMetrics(`${entryPath}/data/${v}`);
    const obj = {
      name: entryPath.split("/").at(-1),
      variant: v,
      ...(entryMd.origin ?? {}),
      ...(entryMd.system ?? {}),
      ...variants[v],
      ...metrics,
    };
    delete obj.variants;
    return obj;
  });
  return await Promise.all(variantMds);
}

export const getLibEntryPaths = async (): Promise<Array<string>> => {
  return (await fsPromises.readdir(LIB_PATH)).map(p => LIB_PATH + p);
}

export const getLangTableData = async (): Promise<Array<any>> => {
  const paths = await getLibEntryPaths();
  const mds = (await Promise.all(paths.map(p => readVariantsFromEntry(p)))).flat();
  return mds;
};

export const getLanguageMetadata = async (name: string): Promise<any> => {
  const basePath = [LIB_PATH, name].join("/");
  const md = await readMetadata(basePath);
  const variants = md.system.variants ?? {};
  const variantPaths = await fsPromises.readdir(basePath + "/data");
  for (const vName of variantPaths) {
    const vPath = [basePath, "data", vName].join("/");
    const vMd = await readMetadata(vPath);
    variants[vName] = {...variants[vName], ...vMd};
  }
  md.system.variants = variants;
  return md;
};
