#!/usr/bin/env python3

from __future__ import annotations
import random


class WaterSample:
    def __init__(
        self,
        solid: int,
        algae: int,
        lime: tuple[int, int, int, int],
        toxin: tuple[int, int, int, int],
    ):
        self.solid = solid
        self.algae = algae
        self.lime = lime
        self.toxin = toxin

    def procedure_dict(self):
        procedures = {
            "1": (self.index1(), self.index1_str()),
            "2": (self.index2(), self.index2_str()),
            "3": (self.index3(), self.index3_str()),
            "4": (self.index4(), self.index4_str()),
            "5": (self.index5(), self.index5_str()),
            "6": (self.index6(), self.index6_str()),
            "overall": (self.overall(), self.overall_str()),
        }

        return procedures

    def water_sample_dict(self):
        sample = {
            "1": (self.index1(), self.index1_str()),
            "2": (self.index2(), self.index2_str()),
            "3": (self.index3(), self.index3_str()),
            "4": (self.index4(), self.index4_str()),
            "5": (self.index5(), self.index5_str()),
            "6": (self.index6(), self.index6_str()),
            "overall": (self.overall(), self.overall_str()),
            "solid": self.solid,
            "algae": self.algae,
            "lime": self.lime,
            "toxin": self.toxin,
        }
        return sample

    def select_procedures(self):
        procedures = [
            (self.index1, self.index1_str),
            (self.index2, self.index2_str),
            (self.index3, self.index3_str),
            (self.index4, self.index4_str),
            (self.index5, self.index5_str),
            (self.index6, self.index6_str),
        ]
        random.shuffle(procedures)
        training_procedures = procedures[:-1]
        training_procedures.append((self.overall, self.overall_str))

        return training_procedures, procedures[-1]

    def index1(self):
        return (self.lime[3] - self.lime[1]) * self.solid

    def index1_str(self):
        return "(Sandstein_4 - Sandstein_2) * Mineralien"

    def index2(self):
        return (2 * self.algae) + min(self.lime)

    def index2_str(self):
        return "(2 * Algen) + Sandstein_min"

    def index3(self):
        return max(self.toxin) + min(self.toxin)

    def index3_str(self):
        return "Gifte_max + Gifte_min"

    def index4(self):
        return (self.solid * 2) - self.toxin[3]

    def index4_str(self):
        return "(Mineralien * 2) - Gifte_4"

    def index5(self):
        return max(self.lime[2], (self.toxin[2] - self.toxin[1]))

    def index5_str(self):
        return "Das Höhere von (Gifte_3 - Gifte_2), (Sandstein_3)"

    def index6(self):
        return min(self.algae, (self.lime[0] + self.toxin[0]))

    def index6_str(self):
        return "Das Kleinere von (Sandstein_1 + Gifte_1), (Algen)"

    def overall(self):
        return 100 - max(
            self.index1(), self.index2(), self.index3(), self.index4(), self.index5()
        )

    def overall_str(self):
        return "100 - dem Höchstem aller Ergebnisse"

    def print_all(self):
        print(f"Solid: {self.solid}")
        print(f"Algae: {self.algae}")
        print(f"Lime: {self.lime}")
        print(f"Toxin: {self.toxin}")
        print(f"Index 1: {self.index1_str()} = {self.index1()}")
        print(f"Index 2: {self.index2_str()} = {self.index2()}")
        print(f"Index 3: {self.index3_str()} = {self.index3()}")
        print(f"Index 4: {self.index4_str()} = {self.index4()}")
        print(f"Index 5: {self.index5_str()} = {self.index5()}")
        print(f"Index 6: {self.index6_str()} = {self.index6()}")
        print(f"Overall Quality: {self.overall_str()} = {self.overall()}")


# No step should produce a negative number, greater/lesser of comparisons should not
# use equal numbers
def constrained_WaterSample():
    water_sample = random_WaterSample()
    resample = True
    while resample:
        water_sample = random_WaterSample()
        resample = False
        # check for negative results
        for proc in water_sample.procedure_dict().keys():
            if water_sample.procedure_dict()[proc][0] < 0:
                resample = True
        # check for greater/lesser equality
        # procedure 5
        if (water_sample.toxin[2] - water_sample.toxin[1]) == water_sample.lime[2]:
            resample = True
        # procedure 6
        if (water_sample.lime[0] + water_sample.toxin[0]) == water_sample.algae:
            resample = True
    return water_sample


def random_WaterSample():
    solid = random.randint(1, 9)
    algae = random.randint(1, 9)
    lime = tuple(random.randint(1, 9) for _ in range(4))
    toxin = tuple(random.randint(1, 9) for _ in range(4))

    return WaterSample(solid, algae, lime, toxin)