from dataclasses import dataclass
from typing import Sequence, List, Dict
import sympy as sp


@dataclass
class Zuverlaessigkeit:

    def redundanzanalyse(self, r_vec: Sequence[float]) -> Dict[str, object]:
        r_s = [sp.sympify(r) for r in r_vec]
        EVi = [float(r * 100) for r in r_s]
        klassen = [self.klassifiziere_ri(float(r)) for r in r_s]

        return {
            "r_i": [float(r) for r in r_s],
            "EVi": EVi,
            "klassen": klassen,
            "r_sum": float(sum(r_s)),
            "min_r": float(min(r_s)),
            "max_r": float(max(r_s)),
        }



    def klassifiziere_ri(self, ri: float) -> str:
        if ri < 0.01:
            return "nicht kontrollierbar"
        elif ri < 0.10:
            return "schlecht kontrollierbar"
        elif ri < 0.30:
            return "ausreichend kontrollierbar"
        elif ri < 0.70:
            return "gut kontrollierbar"
        else:
            return "nahezu vollständig redundant"



    def globaltest(self, sigma0_hat: float, sigma0_apriori: float, F_krit: float):
        s_hat = sp.sympify(sigma0_hat)
        s0 = sp.sympify(sigma0_apriori)
        Fk = sp.sympify(F_krit)

        T_G = (s_hat**2) / (s0**2)
        H0 = bool(T_G <= Fk)

        return {
            "T_G": float(T_G),
            "F_krit": float(Fk),
            "H0_angenommen": H0,
        }



    def data_snooping(
        self,
        v: Sequence[float],
        Qv_diag: Sequence[float],
        r_vec: Sequence[float],
        sigma0_hat: float,
        k: float,
    ) -> List[Dict[str, float | bool]]:

        v_s = [sp.sympify(x) for x in v]
        Qv_s = [sp.sympify(q) for q in Qv_diag]
        r_s = [sp.sympify(r) for r in r_vec]
        s0 = sp.sympify(sigma0_hat)
        k_s = sp.sympify(k)

        results = []

        for vi, Qvi, ri in zip(v_s, Qv_s, r_s):

            s_vi = s0 * sp.sqrt(Qvi)
            NV_i = sp.Abs(vi) / s_vi

            if ri == 0:
                GRZW_i = sp.oo
            else:
                GRZW_i = (s_vi / ri) * k_s

            auff = bool(NV_i > k_s)

            results.append({
                "v_i": float(vi),
                "Qv_i": float(Qvi),
                "r_i": float(ri),
                "s_vi": float(s_vi),
                "NV_i": float(NV_i),
                "GRZW_i": float(GRZW_i if GRZW_i != sp.oo else float("inf")),
                "auffällig": auff,
            })

        return results



    def aeussere_zuverlaessigkeit_EF(self, r_vec: Sequence[float], delta0: float):
        delta = sp.sympify(delta0)
        EF_list = []
        for ri in r_vec:
            ri_s = sp.sympify(ri)
            if ri_s == 0:
                EF = sp.oo
            else:
                EF = sp.sqrt((1 - ri_s) / ri_s) * delta
            EF_list.append(float(EF if EF != sp.oo else float("inf")))

        return EF_list