import { Timestamp } from '@actual-app/crdt';

import * as fs from '../platform/server/fs';
import type { LocalPrefs } from '../types/prefs';

import { Message, sendMessages } from './sync';

export const BUDGET_TYPES = ['report', 'rollover'] as const;
export type BudgetType = (typeof BUDGET_TYPES)[number];

let prefs: LocalPrefs = null;

export async function loadPrefs(id?: string): Promise<LocalPrefs> {
  if (process.env.NODE_ENV === 'test' && !id) {
    prefs = getDefaultPrefs('test', 'test_LocalPrefs');
    return prefs;
  }

  const fullpath = fs.join(fs.getBudgetDir(id), 'metadata.json');

  try {
    prefs = JSON.parse(await fs.readFile(fullpath));
  } catch (e) {
    // If the user messed something up, be flexible and allow them to
    // still load the budget database. Default the budget name to the
    // id.
    prefs = { id, budgetName: id };
  }

  // delete released feature flags
  let releasedFeatures = ['syncAccount'];
  for (const feature of releasedFeatures) {
    delete prefs[`flags.${feature}`];
  }

  // delete legacy notifications
  for (const key of Object.keys(prefs)) {
    if (key.startsWith('notifications.')) {
      delete prefs[key];
    }
  }

  // No matter what is in `id` field, force it to be the current id.
  // This makes it resilient to users moving around folders, etc
  prefs.id = id;
  return prefs;
}

export async function savePrefs(
  prefsToSet: LocalPrefs,
  { avoidSync = false } = {},
): Promise<void> {
  Object.assign(prefs, prefsToSet);

  if (!avoidSync) {
    // Sync whitelisted prefs
    const messages: Message[] = Object.keys(prefsToSet)
      .map(key => {
        if (key === 'budgetType' || key === 'budgetName') {
          return {
            dataset: 'prefs',
            row: key,
            column: 'value',
            value: prefsToSet[key],
            timestamp: Timestamp.send(),
          };
        }
        return null;
      })
      .filter(x => x);

    if (messages.length > 0) {
      await sendMessages(messages);
    }
  }

  if (process.env.NODE_ENV !== 'test') {
    let prefsPath = fs.join(fs.getBudgetDir(prefs.id), 'metadata.json');
    await fs.writeFile(prefsPath, JSON.stringify(prefs));
  }
}

export function unloadPrefs(): void {
  prefs = null;
}

export function getPrefs(): LocalPrefs {
  return prefs;
}

export function getDefaultPrefs(id: string, budgetName: string): LocalPrefs {
  return { id, budgetName };
}