const pizzas = [
    { name: "queen", ingredients: ["🐷​", "🍄‍🟫​", "🍅​", "🧀​"] },
    { name: "cheese", ingredients: ["🧀​", "🍅"] },
    { name: "oriental", ingredients: ["🍅", "🐏​", "🍄‍🟫", "🌶️​"] },
    { name: "royal", ingredients: ["🍅", "🌵​", "🍄‍🟫"] },
    { name: "hawaïenne", ingredients: ["🍍​", "🍅", "🐷​", "🧀​"] }
];

const prices = new Map([
    ["🍅", 1],
    ["🐷", 2],
    ["🌶", 2],
    ["🍄", 5],
    ["🧀", 5],
    ["🐑", 2],
    ["🌵", 10]
]);

//////////////////////////////
// Tableaux 1
// Utilisation de boucles
// Niveau 👶
//////////////////////////////

// 1. Afficher le nom de toutes les pizzas
for (let i = 0; i < pizzas.length; i++) {
    console.log(pizzas[i].name);
}

// 2. Trouvez les pizzas avec du 🧀
for (let i = 0; i < pizzas.length; i++) {
    // vérifier si la pizza contient du fromage
    if (pizzas[i].ingredients.includes("🧀")) {
        console.log(pizzas[i].name);
    }
}

// 3. Donnez moi les pizzas avec plus de 3 ingrédients
for (let i = 0; i < pizzas.length; i++) {
    // vérifie si la liste d'ingrédients est plus longue que 3
    if (pizzas[i].ingredients.length > 3) {
        console.log(pizzas[i].name);
    }
}

// 4. Donnez la liste des ingrédients unique de toutes les pizzas
let uniqueIngredients = [];
for (let i = 0; i < pizzas.length; i++) {
    for (let j = 0; j < pizzas[i].ingredients.length; j++) {
        // vérifie si l'ingrédient n'est pas déjà dans la liste
        if (!uniqueIngredients.includes(pizzas[i].ingredients[j])) {
            // ajoute l'ingrédient à la liste
            uniqueIngredients.push(pizzas[i].ingredients[j]);
        }
    }
}

//////////////////////////////
// Tableaux 2
// Création de fonctions
// Niveau 👦
//////////////////////////////

// 1. Trouvez les pizzas avec un ingrédient quelconque (soit du "🍅" ou du "🧀" ou du "🐑" ...)
const findPizzaWithAnIngredient = (pizzas, ingredient) => {
    // retourne seulement les pizzas
    return pizzas.filter(pizza => {
        // qui contiennent l'ingrédient
        return pizza.ingredients.includes(ingredient)
    });
}

// 2. Trouvez les pizzas avec au moins un ingrédient parmi une liste d'ingrédients
const findPizzaWithSomeIngredients = (pizzas, ingredients) => {
    // retourne seulement les pizzas
    return pizzas.filter(pizza => {
        // qui contiennent au moins un ingrédient
        return ingredients.some(ingredient => pizza.ingredients.includes(ingredient))
    });
}

// 3. Trouvez les pizzas avec tous les ingrédients d'une liste
const findPizzaWithAllIngredients = (pizzas, ingredients) => {
    // retourne seulement les pizzas
    return pizzas.filter(pizza => {
        // qui contiennent TOUS les ingrédients
        return ingredients.every(ingredient => pizza.ingredients.includes(ingredient))
    });
}

// 4. Fonction pour vérifier si une pizza est végétarienne (sans 🐷 ou 🐑)
const animals = ["🐷", "🐑"];
const isVegetarian = (pizza) => {
    // retourne si la pizza ne contient aucun ingrédient animal
    return !pizza.ingredients.some(ingredient => animals.includes(ingredient))
}

// 5. Trouvez les pizzas non végétariennes
const filterNonVegetarian = (pizzas) => {
    // retourne seulement les pizzas
    return pizzas.filter(pizza => {
        // qui ne sont pas végétariennes
        return !isVegetarian(pizza)
    });
}

/*tableau3*/
/*1*/
//////////////////////////////
// Tableaux 3
// utilisation de map, reduce, filter,...
// Niveau 🧑‍💻
//////////////////////////////

// 1. Donnez moi la liste des pizzas avec le nombre d'ingrédients trié par ordre croissant
// sort prend une fonction de comparaison
// qui retourne un nombre négatif si a doit être avant b
// un nombre positif si b doit être avant a
// et 0 si ils sont égaux
// Attention, sort modifie le tableau original
console.log(pizzas.sort((a, b) => a.ingredients.length - b.ingredients.length))

// 2. Trouvez la première pizza avec plus de 3 ingrédients
// find prend une fonction de test
// qui retourne true si l'élément est celui recherché
// Il s'arrête dès qu'il trouve un élément et retourne cet élément
console.log(pizzas.find(pizza => pizza.ingredients.length > 3))

// 3. Trouvez la liste des ingrédients de toutes les pizzas
// reduce prend une fonction qui prend deux arguments
// le premier est l'accumulateur
// le deuxième est l'élément courant
// et retourne l'accumulateur
// le deuxième argument de reduce est la valeur initiale de l'accumulateur
console.log(pizzas.reduce((acc, current) => acc.concat(current.ingredients), []))

// 4. Ajoutez pour chaque pizza l'ingrédient ☘️
// map prend une fonction qui prend un élément en argument
// et retourne un nouvel élément
// le tableau initial n'est donc pas modifié
console.log(pizzas.map(pizza => ({
    name: pizza.name,
    // on copie les ingrédients de la pizza et on ajoute ☘️
    ingredients: [...pizza.ingredients, "☘️"]
})))

// 5. Trouvez pour chaque ingrédient le nombre de pizzas l'utilisant
// utilisation de reduce car on veut transformer un tableau en un objet
// l'accumulateur est un objet
console.log(pizzas.reduce((acc, current) => {
    // Pour chaque pizza, itérer à travers les ingrédients
    current.ingredients.forEach(ingredient => {
        // Vérifier si l'ingrédient est déjà présent dans l'accumulateur
        // Si présent, incrémenter le compteur, sinon ajouter l'ingrédient à l'accumulateur avec un compteur initial de 1 (0 + 1)
        acc[ingredient] = (acc[ingredient] || 0) + 1;
    });
    // Retourner l'accumulateur mis à jour
    return acc;
}, {}))

// 6. Trouvez pour chaque ingrédient la liste des pizzas l'utilisant
// utilisation de reduce car on veut transformer un tableau en un objet
// l'accumulateur est un objet
console.log(pizzas.reduce((acc, current) => {
    // Pour chaque pizza, itérer à travers les ingrédients
    current.ingredients.forEach(ingredient => {
        // Vérifier si l'ingrédient est déjà présent dans l'accumulateur
        // Si présent, ajouter la pizza à la liste, sinon ajouter l'ingrédient à l'accumulateur avec la pizza comme première valeur
        // concat permet de créer une nouvelle liste avec les deux listes concaténées
        acc[ingredient] = (acc[ingredient] || []).concat(current.name);
    });
    // Retourner l'accumulateur mis à jour
    return acc;
}, {}))

// 7. Faite une fonction qui dit si toute les pizza ont un ingrédient donné
const allPizzasHaveIngredient = (pizzas, ingredient) => {
    // every retourne true si tous les éléments du tableau passent le test
    return pizzas.every(pizza => pizza.ingredients.includes(ingredient))
}

//////////////////////////////
// petit bonus
// destructuration
// Niveau 🤓
//////////////////////////////

// 1. Affichez la première pizza et toutes les autres
// destructuration permet de créer des variables à partir des propriétés d'un objet
const [firstPizza, ...otherPizzas] = pizzas;
console.log('pizza 1', firstPizza);
console.log('les autres pizza', otherPizzas);

// 2. Affichez chaque nom de pizza en ajoutant "delamama" à la fin
// destructuration dans une fonction fléchée
// ({name}) prend la propriété name de l'objet en argument
console.log(pizzas.map(({ name }) => `${name}delamama`));

const { name } = pizzas[0];
console.log(name, '===', pizzas[0].name);

//////////////////////////////
// Tableaux 4
// Utilisation d'ensemble (Set et Map)
// Niveau 🧠
//////////////////////////////

// Variables de base
const pizzas2 = [
    { name: "queen", ingredients: ["🐷", "🍄", "🍅", "🧀"] },
    { name: "cheese", ingredients: ["🧀", "🍅"] },
    { name: "oriental", ingredients: ["🍅", "🐑", "🍄", "🌶"] },
    { name: "royal", ingredients: ["🍅", "🌵", "🍄"] },
    { name: "hawaïenne", ingredients: ["🍍", "🍅", "🐷", "🧀"] }
];

const prices2 = new Map([
    ["🍅", 1],
    ["🐷", 2],
    ["🌶", 2],
    ["🍄", 5],
    ["🧀", 5],
    ["🐑", 2],
    ["🌵", 10],
    ["🍍", 3]
]);

// 1. Créez une liste d'ingrédients avec un Set
// Set permet d'avoir une collection de valeurs uniques automatiquement
const allIngredients = new Set(pizzas2.flatMap(pizza => pizza.ingredients));
console.log("Liste des ingrédients uniques:", allIngredients);
// Résultat: Set { '🐷', '🍄', '🍅', '🧀', '🐑', '🌶', '🌵', '🍍' }

// 2. Ajoutez le prix de chaque pizza
// On utilise map pour créer un nouveau tableau avec le prix ajouté
const pizzasWithPrices = pizzas2.map(pizza => ({
    ...pizza,
    price: pizza.ingredients.reduce((total, ingredient) => {
        return total + (prices2.get(ingredient) || 0);
    }, 0)
}));
console.log("Pizzas avec prix:", pizzasWithPrices);

// 3. Calculez le prix de chaque pizza
// Affichage détaillé du calcul
pizzasWithPrices.forEach(pizza => {
    console.log(`${pizza.name}: ${pizza.price}€`);
});
// Résultat:
// queen: 13€ (🐷=2 + 🍄=5 + 🍅=1 + 🧀=5)
// cheese: 6€ (🧀=5 + 🍅=1)
// oriental: 10€ (🍅=1 + 🐑=2 + 🍄=5 + 🌶=2)
// royal: 16€ (🍅=1 + 🌵=10 + 🍄=5)
// hawaïenne: 11€ (🍍=3 + 🍅=1 + 🐷=2 + 🧀=5)

// 4. Déterminez quelles pizzas on peut s'offrir avec 10 €
const budget = 10;
const affordablePizzas = pizzasWithPrices.filter(pizza => pizza.price <= budget);
console.log(`Pizzas qu'on peut s'offrir avec ${budget}€:`);
affordablePizzas.forEach(pizza => {
    console.log(`- ${pizza.name} (${pizza.price}€)`);
});
// Résultat:
// - cheese (6€)
// - oriental (10€)