import BaseDexie, { Table } from "dexie";
import { encrypted, Encryption } from "@pvermeer/dexie-encrypted-addon";
import { Account, AccountsSchema } from "./tables/accounts";
import { Contact, ContactsSchema } from "./tables/contacts";
import {
  MASTER_SETTINGS_KEY,
  Settings,
  SettingsSchema,
} from "./tables/settings";
import { AppString } from "@/constants/app";

// a separate DB because the seed is super-sensitive data
type SensitiveTables = {
  accounts: Table<Account>;
};

type NonsensitiveTables = {
  contacts: Table<Contact>;
  settings: Table<Settings>;
};

/**
 * In order to make the next line be acceptable, the program needs to have its linter suppress a rule:
 *   https://typescript-eslint.io/rules/no-unnecessary-type-constraint/
 *
 * and change *any* to *unknown*
 *
 *   https://9to5answer.com/how-to-bypass-warning-unexpected-any-specify-a-different-type-typescript-eslint-no-explicit-any
 */
export type SensitiveDexie<T extends unknown = SensitiveTables> = BaseDexie & T;
export const accountsDB = new BaseDexie("KickStartAccounts") as SensitiveDexie;
const SensitiveSchemas = Object.assign({}, AccountsSchema);

export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
  BaseDexie & T;
export const db = new BaseDexie("KickStart") as NonsensitiveDexie;
const NonsensitiveSchemas = Object.assign({}, ContactsSchema, SettingsSchema);

/**
 * Needed to enable a special webpack setting to allow *await* below:
 *   https://stackoverflow.com/questions/72474803/error-the-top-level-await-experiment-is-not-enabled-set-experiments-toplevelaw
 */

/**
 * Create password and place password in localStorage.
 *
 * It's good practice to keep the data encrypted at rest, so we'll do that even
 * if the secret is stored right next to the app.
 */
const secret =
  localStorage.getItem("secret") || Encryption.createRandomEncryptionKey();

if (localStorage.getItem("secret") == null) {
  localStorage.setItem("secret", secret);
}

//console.log("IndexedDB Encryption Secret:", secret);
encrypted(accountsDB, { secretKey: secret });
accountsDB.version(1).stores(SensitiveSchemas);

db.version(1).stores(NonsensitiveSchemas);

// initialize, a la https://dexie.org/docs/Tutorial/Design#the-populate-event
db.on("populate", function () {
  // ensure there's an initial entry for settings
  db.settings.add({
    id: MASTER_SETTINGS_KEY,
    apiServer: AppString.DEFAULT_ENDORSER_API_SERVER,
  });
});
