import { app } from 'electron';
import * as fsp from 'fs/promises';
import * as path from 'path';

export interface SavedThemeFileDescriptor {
  fileName: string;
  modifiedAt: number;
  path: string;
}

const SAVED_THEME_FILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*\.json$/;

function resolveSavedThemesPath(): string {
  return path.join(app.getPath('userData'), 'themes');
}

async function ensureSavedThemesPath(): Promise<string> {
  const themesPath = resolveSavedThemesPath();

  await fsp.mkdir(themesPath, { recursive: true });

  return themesPath;
}

function assertSavedThemeFileName(fileName: string): string {
  const normalized = typeof fileName === 'string'
    ? fileName.trim()
    : '';

  if (!SAVED_THEME_FILE_NAME_PATTERN.test(normalized) || normalized.includes('..')) {
    throw new Error('Invalid saved theme file name.');
  }

  return normalized;
}

async function resolveSavedThemeFilePath(fileName: string): Promise<string> {
  const themesPath = await ensureSavedThemesPath();

  return path.join(themesPath, assertSavedThemeFileName(fileName));
}

export async function getSavedThemesPath(): Promise<string> {
  return await ensureSavedThemesPath();
}

export async function listSavedThemes(): Promise<SavedThemeFileDescriptor[]> {
  const themesPath = await ensureSavedThemesPath();
  const entries = await fsp.readdir(themesPath, { withFileTypes: true });
  const files = entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.json'));
  const descriptors = await Promise.all(files.map(async (entry) => {
    const filePath = path.join(themesPath, entry.name);
    const stats = await fsp.stat(filePath);

    return {
      fileName: entry.name,
      modifiedAt: Math.round(stats.mtimeMs),
      path: filePath
    } satisfies SavedThemeFileDescriptor;
  }));

  return descriptors.sort((left, right) => right.modifiedAt - left.modifiedAt || left.fileName.localeCompare(right.fileName));
}

export async function readSavedTheme(fileName: string): Promise<string> {
  const filePath = await resolveSavedThemeFilePath(fileName);

  return await fsp.readFile(filePath, 'utf8');
}

export async function writeSavedTheme(fileName: string, text: string): Promise<boolean> {
  const filePath = await resolveSavedThemeFilePath(fileName);

  await fsp.writeFile(filePath, text, 'utf8');
  return true;
}

export async function deleteSavedTheme(fileName: string): Promise<boolean> {
  const filePath = await resolveSavedThemeFilePath(fileName);

  try {
    await fsp.unlink(filePath);
    return true;
  } catch (error) {
    if ((error as { code?: string }).code === 'ENOENT') {
      return true;
    }

    throw error;
  }
}
