const fs = require('fs');

const file_a = fs.readFileSync('data/a_example', 'utf-8');
const file_b = fs.readFileSync('data/b_little_bit_of_everything.in', 'utf-8');
const file_c = fs.readFileSync('data/c_many_ingredients.in', 'utf-8');
const file_d = fs.readFileSync('data/d_many_pizzas.in', 'utf-8');
const file_e = fs.readFileSync('data/e_many_teams.in', 'utf-8');

let totalScore = 0;

function main(file, char) {
  const myArray = file.split('\n').map((line) => line.split(' '));

  let finalPizzas = [];

  const set = {
    numberOfPizzas: parseInt(myArray[0][0]),
    teams_2: parseInt(myArray[0][1]),
    teams_3: parseInt(myArray[0][2]),
    teams_4: parseInt(myArray[0][3]),
    pizzas: [],
  };

  // Insert all pizzas in set
  for (let i = 1; i < myArray.length - 1; i++) {
    let pizza = {};

    pizza.id = i - 1;
    pizza.numberOfIngredients = parseInt(myArray[i][0]);
    pizza.ingredients = myArray[i].slice(1, myArray[i].length).sort();

    set.pizzas.push(pizza);
  }

  // Sort pizzas in descending order of most ingredients
  set.pizzas.sort((a, b) => b.numberOfIngredients - a.numberOfIngredients);

  let availablePizzas = [...set.pizzas];

  /*
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/////////////////////////////////  2 TEAMS  //////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
*/
  const find_for_two = () => {
    let currentPizza = { ...availablePizzas[0] };
    const selectedPizzas = [{ ...currentPizza }];

    let mostDifferentPizzas = [];
    for (let k = 1; k < availablePizzas.length; k++) {
      let differentIngredients = availablePizzas[k].ingredients.length;

      for (let l = 0; l < availablePizzas[k].ingredients.length; l++) {
        if (
          currentPizza.ingredients.includes(availablePizzas[k].ingredients[l])
        ) {
          differentIngredients--;
        }
      }

      mostDifferentPizzas.push({
        ...availablePizzas[k],
        difference: differentIngredients,
      });
    }

    mostDifferentPizzas.sort((a, b) => b.difference - a.difference);
    selectedPizzas.push({ ...mostDifferentPizzas[0] });

    let totalDifference =
      selectedPizzas[0].numberOfIngredients + selectedPizzas[1].difference;

    finalPizzas.push({
      teamSize: 2,
      pizzas: [...selectedPizzas],
      totalDifference: totalDifference,
    });

    availablePizzas = availablePizzas.filter(
      (p) => !selectedPizzas.map((s) => s.id).includes(p.id)
    );
  };

  /*
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/////////////////////////////////  3 TEAMS  //////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
*/
  const find_for_three = () => {
    let currentPizza = { ...availablePizzas[0] };
    const selectedPizzas = [{ ...currentPizza }];

    let mostDifferentPizzas = [];
    for (let k = 1; k < availablePizzas.length; k++) {
      let differentIngredients = availablePizzas[k].ingredients.length;

      for (let l = 0; l < availablePizzas[k].ingredients.length; l++) {
        if (
          currentPizza.ingredients.includes(availablePizzas[k].ingredients[l])
        ) {
          differentIngredients--;
        }
      }

      mostDifferentPizzas.push({
        ...availablePizzas[k],
        difference: differentIngredients,
      });
    }

    mostDifferentPizzas.sort((a, b) => b.difference - a.difference);
    selectedPizzas.push({ ...mostDifferentPizzas[0] });

    for (let m = 1; m < mostDifferentPizzas.length; m++) {
      let differentIngredients = mostDifferentPizzas[m].difference;

      for (let n = 0; n < mostDifferentPizzas[m].ingredients.length; n++) {
        if (
          mostDifferentPizzas[0].ingredients.includes(
            mostDifferentPizzas[m].ingredients[n]
          )
        ) {
          differentIngredients--;
        }
      }

      mostDifferentPizzas[m].difference = differentIngredients;
    }

    mostDifferentPizzas.sort((a, b) => b.difference - a.difference);
    selectedPizzas.push({ ...mostDifferentPizzas[1] });

    let totalDifference =
      selectedPizzas[0].numberOfIngredients +
      selectedPizzas[1].difference +
      selectedPizzas[2].difference;

    finalPizzas.push({
      teamSize: 3,
      pizzas: [...selectedPizzas],
      totalDifference: totalDifference,
    });

    availablePizzas = availablePizzas.filter(
      (p) => !selectedPizzas.map((s) => s.id).includes(p.id)
    );
  };

  /*
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/////////////////////////////////  4 TEAMS  //////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
*/
  const find_for_four = () => {
    let currentPizza = { ...availablePizzas[0] };
    const selectedPizzas = [{ ...currentPizza }];

    let mostDifferentPizzas = [];
    for (let k = 1; k < availablePizzas.length; k++) {
      let differentIngredients = availablePizzas[k].ingredients.length;

      for (let l = 0; l < availablePizzas[k].ingredients.length; l++) {
        if (
          currentPizza.ingredients.includes(availablePizzas[k].ingredients[l])
        ) {
          differentIngredients--;
        }
      }

      mostDifferentPizzas.push({
        ...availablePizzas[k],
        difference: differentIngredients,
      });
    }

    mostDifferentPizzas.sort((a, b) => b.difference - a.difference);
    selectedPizzas.push({ ...mostDifferentPizzas[0] });

    for (let m = 1; m < mostDifferentPizzas.length; m++) {
      let differentIngredients = mostDifferentPizzas[m].difference;

      for (let n = 0; n < mostDifferentPizzas[m].ingredients.length; n++) {
        if (
          mostDifferentPizzas[0].ingredients.includes(
            mostDifferentPizzas[m].ingredients[n]
          )
        ) {
          differentIngredients--;
        }
      }

      mostDifferentPizzas[m].difference = differentIngredients;
    }

    mostDifferentPizzas.sort((a, b) => b.difference - a.difference);
    selectedPizzas.push({ ...mostDifferentPizzas[1] });

    for (let o = 2; o < mostDifferentPizzas.length; o++) {
      let differentIngredients = mostDifferentPizzas[o].difference;

      for (let p = 0; p < mostDifferentPizzas[o].ingredients.length; p++) {
        if (
          mostDifferentPizzas[1].ingredients.includes(
            mostDifferentPizzas[o].ingredients[p]
          )
        ) {
          differentIngredients--;
        }
      }

      mostDifferentPizzas[o].difference = differentIngredients;
    }

    mostDifferentPizzas.sort((a, b) => b.difference - a.difference);
    selectedPizzas.push({ ...mostDifferentPizzas[2] });

    let totalDifference =
      selectedPizzas[0].numberOfIngredients +
      selectedPizzas[1].difference +
      selectedPizzas[2].difference +
      selectedPizzas[3].difference;

    finalPizzas.push({
      teamSize: 4,
      pizzas: [...selectedPizzas],
      totalDifference: totalDifference,
    });

    availablePizzas = availablePizzas.filter(
      (p) => !selectedPizzas.map((s) => s.id).includes(p.id)
    );
  };

  while (availablePizzas.length > 0) {
    if (
      set.teams_2 + set.teams_3 + set.teams_4 === 0 ||
      (availablePizzas.length === 2 && set.teams_2 === 0) ||
      (availablePizzas.length === 3 && set.teams_3 === 0) ||
      availablePizzas.length < 2
    ) {
      break;
    }

    if (
      (availablePizzas.length % 2 !== 0 || set.teams_2 + set.teams_4 === 0) &&
      set.teams_3 > 0 &&
      availablePizzas.length >= 3
    ) {
      find_for_three();
      set.teams_3--;
    } else {
      // if (availablePizzas.length >= 2 && set.teams_2 > 0) {
      //   find_for_two();
      //   set.teams_2--;
      // } else {
      //   find_for_four();
      //   set.teams_4--;
      // }
      if (availablePizzas.length >= 4 && set.teams_4 > 0) {
        find_for_four();
        set.teams_4--;
      } else {
        find_for_two();
        set.teams_2--;
      }
    }
  }

  const finalScore = finalPizzas.reduce(
    (result, item) => result + item.totalDifference * item.totalDifference,
    0
  );

  console.log(`Score ${char}: ${finalScore}`);
  totalScore += finalScore;

  const fileResult = [finalPizzas.length];
  finalPizzas.forEach((item) => {
    let line = [item.teamSize];

    item.pizzas.forEach((pizza) => {
      line.push(pizza.id);
    });

    fileResult.push(line.join(' '));
  });

  fs.writeFileSync(`output/result_${char}.txt`, fileResult.join('\n'));
}

main(file_a, 'A');
main(file_b, 'B');
main(file_c, 'C');
main(file_d, 'D');
main(file_e, 'E');

console.log(`Total Score: ${totalScore}`);
