/**
 * Servicio: fsScanner
 *
 * Este módulo proporciona la función `scanDirectory` que recorre recursivamente
 * un directorio (ignorando archivos y carpetas que comienzan por `.`) y devuelve
 * una lista de metadatos de ficheros encontrados. Cada entrada contiene el
 * `path` completo, `filename`, `name`, `size`, `format` detectado por extensión
 * y `isArchive` indicando si se trata de un contenedor (zip/7z/chd).
 *
 * Se usa desde el importService para listar las ROMs/archivos que deben ser
 * procesados/hashed y persistidos.
 */
import path from 'path';
import { promises as fsPromises } from 'fs';
import { detectFormat } from '../lib/fileTypeDetector';
import { listArchiveEntries } from './archiveReader';

const DEFAULT_ARCHIVE_MAX_ENTRIES = 1000;
function getArchiveMaxEntries(): number {
  const parsed = parseInt(process.env.ARCHIVE_MAX_ENTRIES ?? '', 10);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_ARCHIVE_MAX_ENTRIES;
}

export async function scanDirectory(dirPath: string): Promise<any[]> {
  const results: any[] = [];
  let archiveEntriesAdded = 0;

  async function walk(dir: string) {
    const entries = await fsPromises.readdir(dir, { withFileTypes: true });

    for (const entry of entries) {
      if (entry.name.startsWith('.')) continue; // ignore dotfiles

      const full = path.join(dir, entry.name);

      if (entry.isDirectory()) {
        await walk(full);
        continue;
      }

      if (entry.isFile()) {
        const stat = await fsPromises.stat(full);
        const format = detectFormat(entry.name);
        const isArchive = ['zip', '7z', 'chd'].includes(format);

        results.push({
          path: full,
          filename: entry.name,
          name: entry.name,
          size: stat.size,
          format,
          isArchive,
        });

        if (isArchive) {
          try {
            const entries = await listArchiveEntries(full);

            const maxEntries = getArchiveMaxEntries();
            for (const e of entries) {
              if (archiveEntriesAdded >= maxEntries) break;
              if (!e || !e.name) continue;

              // Normalize entry path using posix rules and avoid traversal/absolute paths
              const normalized = path.posix.normalize(e.name);
              const parts = normalized.split('/').filter(Boolean);
              if (parts.includes('..') || path.posix.isAbsolute(normalized)) continue;

              results.push({
                path: `${full}::${normalized}`,
                containerPath: full,
                entryPath: normalized,
                filename: path.posix.basename(normalized),
                name: normalized,
                size: e.size,
                format: detectFormat(normalized),
                isArchive: false,
                isArchiveEntry: true,
              });

              archiveEntriesAdded++;
            }
          } catch (err) {
            // log for diagnostics but continue
            try {
              // eslint-disable-next-line no-console
              console.debug('fsScanner: listArchiveEntries failed for', full, err);
            } catch (e) {}
          }
        }
      }
    }
  }

  await walk(dirPath);
  return results;
}

export default scanDirectory;
