const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;

const entryFile = path.resolve(__dirname, "index.js");
const srcDir = path.resolve(__dirname, "src");

// Extensions de fichiers à analyser
const scriptExtensions = [".js", ".jsx", ".ts", ".tsx", ".web.js"];
const imageExtensions = [".png", ".jpg", ".jpeg", ".gif", ".svg"];

// Fonction pour obtenir tous les fichiers dans un dossier avec des extensions spécifiques
function getAllFiles(dir, extensions, fileList = []) {
  const files = fs.readdirSync(dir);
  files.forEach(function (file) {
    const filePath = path.join(dir, file);
    const stat = fs.statSync(filePath);
    if (stat.isDirectory()) {
      getAllFiles(filePath, extensions, fileList);
    } else if (extensions.includes(path.extname(file))) {
      fileList.push(filePath);
    }
  });
  return fileList;
}

// Vérifie si un chemin est un fichier valide
function isValidFile(filePath) {
  return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
}

// Résout le chemin de l'import en un fichier valide
function resolveImport(filePath, importPath) {
  let importedFile = path.resolve(path.dirname(filePath), importPath);

  // Liste des extensions à tester, y compris .web.js
  const allExtensions = scriptExtensions;

  // Si le chemin n'a pas d'extension, essayer avec différentes extensions
  if (!path.extname(importedFile)) {
    for (const ext of allExtensions) {
      if (isValidFile(importedFile + ext)) {
        return importedFile + ext;
      }
    }
  }

  // Si un fichier avec l'extension actuelle existe, le retourner
  if (isValidFile(importedFile)) {
    return importedFile;
  }

  // Si le chemin est un répertoire, chercher un index avec les extensions
  if (fs.existsSync(importedFile) && fs.statSync(importedFile).isDirectory()) {
    const indexFiles = allExtensions.map((ext) => "index" + ext);
    for (const indexFile of indexFiles) {
      const indexFilePath = path.join(importedFile, indexFile);
      if (isValidFile(indexFilePath)) {
        return indexFilePath;
      }
    }
  }

  // Aucun fichier valide trouvé
  return null;
}

// Analyse des fichiers pour trouver les imports
function getDependencies(
  filePath,
  visitedFiles = new Set(),
  usedDependencies = new Set(),
  usedFiles = new Set(),
  usedAssets = new Set()
) {
  if (visitedFiles.has(filePath))
    return { usedDependencies, usedFiles, usedAssets };
  visitedFiles.add(filePath);
  usedFiles.add(filePath);

  const content = fs.readFileSync(filePath, "utf-8");
  let ast;
  try {
    ast = parser.parse(content, {
      sourceType: "module",
      plugins: ["jsx", "typescript", "classProperties", "dynamicImport"],
    });
  } catch (error) {
    console.error(`Erreur lors de l'analyse du fichier ${filePath}:`, error);
    return { usedDependencies, usedFiles, usedAssets };
  }

  traverse(ast, {
    ImportDeclaration({ node }) {
      const importPath = node.source.value;
      handleImport(
        filePath,
        importPath,
        visitedFiles,
        usedDependencies,
        usedFiles,
        usedAssets
      );
    },
    CallExpression({ node }) {
      if (
        node.callee.type === "Import" ||
        (node.callee.name === "require" && node.arguments.length)
      ) {
        const importArg = node.arguments[0];
        if (importArg && importArg.type === "StringLiteral") {
          const importPath = importArg.value;
          handleImport(
            filePath,
            importPath,
            visitedFiles,
            usedDependencies,
            usedFiles,
            usedAssets
          );
        }
      }
    },
  });

  // Vérifier si un fichier .web.js correspondant existe
  if (filePath.endsWith(".js")) {
    const webFilePath = filePath.replace(/\.js$/, ".web.js");
    if (isValidFile(webFilePath)) {
      getDependencies(
        webFilePath,
        visitedFiles,
        usedDependencies,
        usedFiles,
        usedAssets
      );
    }
  }

  return { usedDependencies, usedFiles, usedAssets };
}

// Fonction pour gérer les imports
function handleImport(
  filePath,
  importPath,
  visitedFiles,
  usedDependencies,
  usedFiles,
  usedAssets
) {
  if (importPath.startsWith(".")) {
    // Chemin relatif
    const resolvedPath = resolveImport(filePath, importPath);
    if (resolvedPath) {
      const ext = path.extname(resolvedPath);
      if (scriptExtensions.includes(ext)) {
        getDependencies(
          resolvedPath,
          visitedFiles,
          usedDependencies,
          usedFiles,
          usedAssets
        );
      } else if (imageExtensions.includes(ext)) {
        usedAssets.add(resolvedPath);
      }
    }
  } else {
    // Dépendance de node_modules
    const dep = importPath.split("/")[0];
    usedDependencies.add(dep);
  }
}

(async () => {
  // Étape 1: Obtenir tous les fichiers utilisés
  const allScriptFiles = getAllFiles(srcDir, scriptExtensions);
  const allAssetFiles = getAllFiles(srcDir, imageExtensions);

  const { usedDependencies, usedFiles, usedAssets } =
    getDependencies(entryFile);

  // Étape 2: Supprimer les fichiers scripts inutilisés
  const unusedScriptFiles = allScriptFiles.filter(
    (file) => !usedFiles.has(file)
  );

  unusedScriptFiles.forEach((file) => {
    fs.unlinkSync(file);
    console.log(`Fichier script supprimé: ${file}`);
  });

  // Étape 3: Supprimer les images non utilisées
  const unusedAssetFiles = allAssetFiles.filter(
    (file) => !usedAssets.has(file)
  );

  unusedAssetFiles.forEach((file) => {
    fs.unlinkSync(file);
    console.log(`Fichier image supprimé: ${file}`);
  });

  // Étape 4: Optimiser les images utilisées sans perte de qualité
  async function optimizeImages(usedAssets) {
    // Import dynamique des modules ES
    const imagemin = (await import("imagemin")).default;
    const imageminOptipng = (await import("imagemin-optipng")).default;
    const imageminJpegtran = (await import("imagemin-jpegtran")).default;
    const imageminGifsicle = (await import("imagemin-gifsicle")).default;
    const imageminSvgo = (await import("imagemin-svgo")).default;

    for (const file of usedAssets) {
      const ext = path.extname(file).toLowerCase();
      const plugins = [];

      if (ext === ".png") {
        plugins.push(imageminOptipng({ optimizationLevel: 3 }));
      } else if (ext === ".jpg" || ext === ".jpeg") {
        plugins.push(imageminJpegtran({ progressive: true }));
      } else if (ext === ".gif") {
        plugins.push(imageminGifsicle({ optimizationLevel: 3 }));
      } else if (ext === ".svg") {
        plugins.push(imageminSvgo());
      } else {
        continue;
      }

      try {
        const optimized = await imagemin([file], {
          destination: path.dirname(file),
          plugins: plugins,
        });

        if (optimized && optimized.length > 0) {
          console.log(`Image optimisée: ${file}`);
        } else {
          console.log(`Image déjà optimisée ou non optimisable: ${file}`);
        }
      } catch (error) {
        console.error(
          `Erreur lors de l'optimisation de l'image ${file}:`,
          error
        );
      }
    }
  }

  await optimizeImages(usedAssets);
})();
