package games.colonier.ld44.simulation;

import games.colonier.ld44.chemistry.Molecule;
import games.colonier.ld44.chemistry.MoleculeRule;
import games.colonier.ld44.chemistry.Reaction;
import games.colonier.ld44.chemistry.Symptom;

import java.util.*;

public class Simulation {

    public Map <Symptom, Integer> symptomResults = new HashMap<> ();
    public float predictedSeverity;
    public Boolean worksAgainstDisease;

    // public final MoleculeRule diseaseRule;
    public final Molecule diseaseMolecule;
    public final Molecule molecule;
    public final SimulationParameters simulationParameters;
    public Molecule reactedDiseaseMolecule;

    public Simulation (
            Molecule diseaseMolecule,
            Molecule molecule,
            SimulationParameters simulationParameters
    ) {
        this.diseaseMolecule = diseaseMolecule;
        this.molecule = molecule;
        this.simulationParameters = simulationParameters;
    }

    public void simulate () {

        Random random = new Random ();

        Molecule mDisease = diseaseMolecule.copy ();
        Molecule mMedicine = molecule.copy ();

        List <Symptom> originalSymptoms = mDisease.getSymptoms ();

        Reaction reaction = new Reaction (mDisease, mMedicine);
        reaction.react ();

        worksAgainstDisease = true;
        for (Symptom newSymptom : mDisease.getSymptoms ()) {
            if (originalSymptoms.contains (newSymptom)) worksAgainstDisease = false;
        }

        reactedDiseaseMolecule = mDisease;

        List <SimulationParticipant> participants = new ArrayList<> ();

        for (int i = 0; i < simulationParameters.numTestParticipants; i++) {

            SimulationParticipant participant = new SimulationParticipant (i);

            for (Symptom symptom : Symptom.values ()) {

                if (symptom.rule.appliesTo (mDisease)) {

                    float randomValue = random.nextFloat ();
                    if (randomValue < simulationParameters.existentSymptomSkipProbability) {
                        participant.symptomMap.put (symptom, false);
                    } else {
                        participant.symptomMap.put (symptom, true);
                    }

                } else {

                    float randomValue = random.nextFloat ();
                    if (randomValue < simulationParameters.nonexistentSymptomProbability) {
                        participant.symptomMap.put (symptom, true);
                    } else {
                        participant.symptomMap.put (symptom, false);
                    }

                }

            }

            participants.add (participant);

        }

        predictedSeverity = 0.0f;

        for (SimulationParticipant sp : participants) {

            for (Symptom sy : sp.symptomMap.keySet ()) {

                symptomResults.compute (
                        sy,
                        (symptom, integer) -> (integer == null ? 0 : integer) + (sp.symptomMap.get (sy) ? 1 : 0)
                );

                if (sp.symptomMap.get (sy)) {
                    predictedSeverity += sy.severity;
                }

            }

        }

        predictedSeverity /= (float) participants.size ();

    }

}
