import { findDefaultSchema, findEngineDriver, isCompositeDbName } from 'dbgate-tools';
import { currentDatabase, getExtensions, getOpenedTabs, loadingSchemaLists, openedTabs } from '../stores';
import _ from 'lodash';
import { getSchemaList } from './metadataLoaders';
import { showSnackbarError } from './snackbar';

export class LoadingToken {
  isCanceled = false;

  cancel() {
    this.isCanceled = true;
  }
}

export function sleep(milliseconds) {
  return new Promise(resolve => window.setTimeout(() => resolve(null), milliseconds));
}

export function changeTab(tabid, changeFunc) {
  openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? changeFunc(tab) : tab)));
}

export function markTabUnsaved(tabid) {
  const tab = getOpenedTabs().find(x => x.tabid == tabid);
  if (tab.unsaved) return;
  openedTabs.update(files =>
    files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: true, tabPreviewMode: false } : tab))
  );
}

export function markTabSaved(tabid) {
  openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: false } : tab)));
}

export function setSelectedTabFunc(files, tabid, additionalProps = {}) {
  return [
    ...(files || [])
      .filter(x => x.tabid != tabid)
      .map(x => ({
        ...x,
        selected: false,
        focused: false,
      })),
    ...(files || [])
      .filter(x => x.tabid == tabid)
      .map(x => ({
        ...x,
        selected: true,
        focused: false,
        ...additionalProps,
      })),
  ];
}

export function setSelectedTab(tabid) {
  openedTabs.update(tabs => setSelectedTabFunc(tabs, tabid));
}

export function getObjectTypeFieldLabel(objectTypeField, driver?) {
  if (objectTypeField == 'matviews') return 'Materialized Views';
  if (objectTypeField == 'collections') return _.startCase(driver?.collectionPluralLabel) ?? 'Collections/Containers';
  return _.startCase(objectTypeField);
}

export async function asyncFilter(arr, predicate) {
  const results = await Promise.all(arr.map(predicate));

  return arr.filter((_v, index) => results[index]);
}

export function isMac() {
  // @ts-ignore
  const platform = navigator?.platform || navigator?.userAgentData?.platform || 'unknown';
  return platform.toUpperCase().indexOf('MAC') >= 0;
}

export function formatKeyText(keyText: string): string {
  if (isMac()) {
    return keyText
      .replace(/CtrlOrCommand\+/g, '⌘ ')
      .replace(/Shift\+/g, '⇧ ')
      .replace(/Alt\+/g, '⌥ ')
      .replace(/Command\+/g, '⌘ ')
      .replace(/Ctrl\+/g, '⌃ ')
      .replace(/Backspace/g, '⌫ ');
  }
  return keyText.replace(/CtrlOrCommand\+/g, 'Ctrl+');
}

export function resolveKeyText(keyText: string): string {
  if (isMac()) {
    return keyText.replace(/CtrlOrCommand\+/g, 'Command+');
  }
  return keyText.replace(/CtrlOrCommand\+/g, 'Ctrl+');
}

export function isCtrlOrCommandKey(event) {
  if (isMac()) {
    return event.metaKey;
  }
  return event.ctrlKey;
}

export async function loadSchemaList(conid, database) {
  try {
    loadingSchemaLists.update(x => ({ ...x, [`${conid}::${database}`]: true }));
    const schemas = await getSchemaList({ conid, database });
    if (schemas.errorMessage) {
      showSnackbarError(`Error loading schemas: ${schemas.errorMessage}`);
      console.error('Error loading schemas', schemas.errorMessage);
      return;
    }
    return schemas;
  } finally {
    loadingSchemaLists.update(x => _.omit(x, [`${conid}::${database}`]));
  }
}

export async function switchCurrentDatabase(data) {
  if (data?.connection?.useSeparateSchemas && !isCompositeDbName(data.name)) {
    const conid = data.connection._id;
    const database = data.name;
    const storageKey = `selected-schema-${conid}-${database}`;
    const schemaInStorage = localStorage.getItem(storageKey);
    const schemas = await loadSchemaList(conid, database);
    if (!schemas) return;
    const driver = findEngineDriver(data.connection, getExtensions());
    const defaultSchema = findDefaultSchema(schemas, driver?.dialect, schemaInStorage);
    currentDatabase.set({
      ...data,
      name: `${data.name}::${defaultSchema}`,
    });
  } else {
    currentDatabase.set(data);
  }
}

export function getKeyTextFromEvent(e) {
  let keyText = '';
  if (e.ctrlKey) keyText += 'Ctrl+';
  if (e.metaKey) keyText += 'Command+';
  if (e.shiftKey) keyText += 'Shift+';
  if (e.altKey) keyText += 'Alt+';
  keyText += e.key;
  return keyText;
}
