import { KVStore } from "../../plugos/lib/kv_store.ts";
import type { SysCallMapping } from "../../plugos/system.ts";

export type KV = {
  key: string;
  value: any;
};

// Keyspace:
// ["index", page, key] -> value
// ["indexByKey", key, page] -> value

const sep = "!";

/**
 * Implements the index syscalls using Deno's KV store.
 * @param dbFile
 * @returns
 */
export function pageIndexSyscalls(kv: KVStore): SysCallMapping {
  const apiObj: SysCallMapping = {
    "index.set": (_ctx, page: string, key: string, value: any) => {
      return kv.batchSet(
        [{
          key: `index${sep}${page}${sep}${key}`,
          value,
        }, {
          key: `indexByKey${sep}${key}${sep}${page}`,
          value,
        }],
      );
    },
    "index.batchSet": (_ctx, page: string, kvs: KV[]) => {
      const batch: KV[] = [];
      for (const { key, value } of kvs) {
        batch.push({
          key: `index${sep}${page}${sep}${key}`,
          value,
        }, {
          key: `indexByKey${sep}${key}${sep}${page}`,
          value,
        });
      }
      return kv.batchSet(batch);
    },
    "index.delete": (_ctx, page: string, key: string) => {
      return kv.batchDelete([
        `index${sep}${page}${sep}${key}`,
        `indexByKey${sep}${key}${sep}${page}`,
      ]);
    },
    "index.get": (_ctx, page: string, key: string) => {
      return kv.get(`index${sep}${page}${sep}${key}`);
    },
    "index.queryPrefix": async (_ctx, prefix: string) => {
      const results: { key: string; page: string; value: any }[] = [];
      for (
        const result of await kv.queryPrefix(`indexByKey!${prefix}`)
      ) {
        const [_ns, key, page] = result.key.split(sep);
        results.push({
          key,
          page,
          value: result.value,
        });
      }
      return results;
    },
    "index.clearPageIndexForPage": async (ctx, page: string) => {
      await apiObj["index.deletePrefixForPage"](ctx, page, "");
    },
    "index.deletePrefixForPage": async (_ctx, page: string, prefix: string) => {
      const allKeys: string[] = [];
      for (
        const result of await kv.queryPrefix(
          `index${sep}${page}${sep}${prefix}`,
        )
      ) {
        const [_ns, page, key] = result.key.split(sep);
        allKeys.push(
          `index${sep}${page}${sep}${key}`,
          `indexByKey${sep}${key}${sep}${page}`,
        );
      }
      return kv.batchDelete(allKeys);
    },
    "index.clearPageIndex": async () => {
      const allKeys: string[] = [];
      for (const result of await kv.queryPrefix(`index${sep}`)) {
        const [_ns, page, key] = result.key.split(sep);
        allKeys.push(
          `index${sep}${page}${sep}${key}`,
          `indexByKey${sep}${key}${sep}${page}`,
        );
      }
      return kv.batchDelete(allKeys);
    },
  };
  return apiObj;
}
