/**
 * Servicio: importService
 *
 * Orquesta el proceso de importación de ROMs desde un directorio:
 * 1. Lista archivos usando `scanDirectory`.
 * 2. Calcula hashes y tamaño con `computeHashes` (streaming).
 * 3. Normaliza el nombre a un `slug` y, si `persist` es true, crea/obtiene
 *    el `Game` correspondiente y hace `upsert` del `RomFile` en Prisma.
 *
 * `importDirectory` devuelve un resumen con contadores `{ processed, createdCount, upserted }`.
 */
import path from 'path';
import { promises as fsPromises } from 'fs';
import { scanDirectory } from './fsScanner';
import { computeHashes } from './checksumService';
import prisma from '../plugins/prisma';

/**
 * Crea un `slug` a partir de un nombre legible. Usado para generar slugs
 * por defecto al crear entradas `Game` cuando no existe la coincidencia.
 */
export function createSlug(name: string): string {
  return name
    .toString()
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

export async function importDirectory(
  options?: { dir?: string; persist?: boolean },
  logger: { warn?: (msg: any, ...args: any[]) => void } = console
) {
  const providedDir = options?.dir;
  const dir = providedDir ?? process.env.ROMS_PATH ?? path.join(process.cwd(), 'roms');
  const persist = options?.persist !== undefined ? options.persist : true;

  // Si no se pasó explícitamente la ruta, validamos que exista y sea un directorio
  if (!providedDir) {
    try {
      const stat = await fsPromises.stat(dir);
      if (!stat.isDirectory()) {
        logger.warn?.({ dir }, 'importDirectory: ruta no es un directorio');
        return { processed: 0, createdCount: 0, upserted: 0 };
      }
    } catch (err) {
      logger.warn?.({ err, dir }, 'importDirectory: ruta no accesible, abortando import');
      return { processed: 0, createdCount: 0, upserted: 0 };
    }
  }

  let files: any[] = [];
  try {
    files = await scanDirectory(dir as string);
  } catch (err) {
    logger.warn?.({ err, dir }, 'importDirectory: error listando directorio');
    return { processed: 0, createdCount: 0, upserted: 0 };
  }

  let processed = 0;
  let createdCount = 0;
  let upserted = 0;

  for (const file of files) {
    processed++;

    try {
      const hashes = await computeHashes(file.path);
      const checksum = hashes.md5;
      const size = hashes.size;

      const baseName = path.parse(file.filename).name;
      const slug = createSlug(baseName);

      let game = null;

      if (persist) {
        game = await prisma.game.findUnique({ where: { slug } });

        if (!game) {
          game = await prisma.game.create({ data: { title: baseName, slug } });
          createdCount++;
        }

        await prisma.romFile.upsert({
          where: { checksum },
          update: { lastSeenAt: new Date(), size, hashes: JSON.stringify(hashes) },
          create: {
            path: file.path,
            filename: file.filename,
            checksum,
            size,
            format: file.format,
            hashes: JSON.stringify(hashes),
            gameId: game?.id,
          },
        });

        upserted++;
      }
    } catch (err) {
      logger.warn?.({ err, file }, 'importDirectory: error procesando fichero, se continúa con el siguiente');
      continue;
    }
  }

  return { processed, createdCount, upserted };
}

export default importDirectory;
