import { promises as fs } from 'fs';
import path from 'path';
import { allowLocalFallback, storageDataDirectory } from '../config/env';

const dataDirectory = storageDataDirectory;

type LocalStoreMode = 'fallback' | 'persistent';

type LocalStoreOptions = {
  mode?: LocalStoreMode;
};

export class LocalFallbackDisabledError extends Error {
  constructor(fileName: string) {
    super(
      `El almacenamiento local de respaldo esta deshabilitado para ${fileName}. Configura PostgreSQL o habilita ALLOW_LOCAL_FALLBACK de forma explicita.`,
    );
    this.name = 'LocalFallbackDisabledError';
  }
}

const assertLocalStoreAllowed = (fileName: string, options?: LocalStoreOptions) => {
  if ((options?.mode ?? 'fallback') === 'persistent') {
    return;
  }

  if (!allowLocalFallback) {
    throw new LocalFallbackDisabledError(fileName);
  }
};

const ensureDataFile = async <T>(
  fileName: string,
  seedFactory: () => Promise<T> | T,
  options?: LocalStoreOptions,
) => {
  assertLocalStoreAllowed(fileName, options);
  const filePath = path.join(dataDirectory, fileName);

  try {
    await fs.access(filePath);
  } catch {
    const seedData = await seedFactory();
    await fs.mkdir(dataDirectory, { recursive: true });
    await fs.writeFile(filePath, JSON.stringify(seedData, null, 2));
  }

  return filePath;
};

export const readDataFile = async <T>(
  fileName: string,
  seedFactory: () => Promise<T> | T,
  options?: LocalStoreOptions,
) => {
  const filePath = await ensureDataFile(fileName, seedFactory, options);
  const content = await fs.readFile(filePath, 'utf-8');
  return JSON.parse(content) as T;
};

export const writeDataFile = async <T>(fileName: string, data: T, options?: LocalStoreOptions) => {
  assertLocalStoreAllowed(fileName, options);
  const filePath = path.join(dataDirectory, fileName);
  await fs.mkdir(dataDirectory, { recursive: true });
  await fs.writeFile(filePath, JSON.stringify(data, null, 2));
};

export const readPersistentDataFile = async <T>(fileName: string, seedFactory: () => Promise<T> | T) =>
  readDataFile(fileName, seedFactory, { mode: 'persistent' });

export const writePersistentDataFile = async <T>(fileName: string, data: T) =>
  writeDataFile(fileName, data, { mode: 'persistent' });
