from __future__ import annotations
from algorithm.MaxCAFAlgorithm import MaxCAFAlgorithm
from algorithm.MaxRAFAlgorithm import MaxRAFAlgorithm
from model.Reaction import Reaction
from model.ReactionSystem import ReactionSystem

from tqdm import tqdm
import copy
import sys
import os
sys.path.insert(0, os.path.abspath(
    os.path.join(os.path.dirname(__file__), '.')))


class GreedilyGrowMaxCAF2MaxRAF():

    @property
    def description(self):
        return "greedily grow maxCAF to maxRAF by making reactions spontaneous"

    def apply(input_reaction_system: ReactionSystem) -> None:
        """generate a minimum max caf as large as max raf by removing catalysts and inhibitors

        Args:
            input_reaction_system (ReactionSystem): System to run both algorithms on
        """        
        
        max_caf = MaxCAFAlgorithm().apply(input_reaction_system)
        max_raf = MaxRAFAlgorithm().apply(input_reaction_system)

        remaining_reactions = [r for r in max_raf.reactions if not (
            r.name in max_caf.get_reaction_names())]

        augmented_reactions = []
        augmented_system = copy.copy(max_raf)
        augmented_caf_size = max_caf.size

        while (augmented_caf_size < max_raf.size):
            best: tuple[Reaction, int] = ()
            cache = []
            for name in remaining_reactions:
                cache.append(GreedilyGrowMaxCAF2MaxRAF().apply_best_finder_helper(
                    name, max_raf, augmented_system))
            best = max(cache, key=lambda x: x[1])

            if best != ():
                augmented_reaction = best[0]
                augmented_caf_size = best[1]
                augmented_system.replace_named_reaction(
                    augmented_reaction.name, augmented_reaction)

                augmented_reactions.append(augmented_reaction.name)
                remaining_reactions.remove(augmented_reaction.name)
            else:
                tqdm.write("No valid greedy choice found")

        result = (max_caf.size, max_raf.size, augmented_reactions)
        message = ""

        if len(result[2]) == 0 and result[0] == result[1]:
            message = "Greedily grow MaxCAF to MaxRAF: no reactions required to be spontaneous, because MaxCAF=MaxRAF"
        else:
            message = "Greedily grow MaxCAF (size " + result[0] + ") to MaxRAF (size " + result[1] + \
                "): required %d reactions to be spontaneous: %s"  # UNKLAR, was wird wieder gegeben

    def apply_best_finder_helper(reaction_name: str, max_raf: ReactionSystem, augmented_system: ReactionSystem) -> tuple[Reaction, int]:
        """Generates new max caf with one reaction replaced with a copy without catalysts and inhibitors.

        Args:
            reaction_name (str): name of reaction to be made spontaneous
            max_raf (ReactionSystem): system generated by max raf
            augmented_system (ReactionSystem): max raf system with replaced reactions

        Returns:
            tuple[Reaction, int]: new max caf system with replaced reaction and size of that max caf system
        """        
        augmented_reaction: Reaction = copy.deepcopy(
            max_raf.get_reaction_by_name(reaction_name))
        augmented_reaction.catalysts = ""
        augmented_reaction.inhibitions.clear

        working_system = copy.copy(augmented_system)
        working_system.replace_named_reaction(
            reaction_name, augmented_reaction)

        working_max_caf: ReactionSystem = MaxCAFAlgorithm.apply(working_system)
        return (augmented_reaction, working_max_caf.size)
