from typing import Dict, List

from .utils import freeze


class QualitativeScale:
    DEFAULT_NUM_TO_TEXT: Dict[str, int] = {
        5: "Very High",
        4: "High",
        3: "Moderate",
        2: "Low",
        1: "Very Low",
        0: "Very Low",
    }

    DEFAULT_RANGE_TO_TEXT: List[Dict] = [
        {"value": 1, "low": 1, "high": 5},
        {"value": 2, "low": 5, "high": 9},
        {"value": 3, "low": 9, "high": 13},
        {"value": 4, "low": 13, "high": 20},
        {"value": 5, "low": 20, "high": 26},
    ]

    DEFAULT_TEF: List[Dict] = [
        {"value": 1, "low": 0.01, "high": 0.1},
        {"value": 2, "low": 0.1, "high": 1},
        {"value": 3, "low": 1, "high": 10},
        {"value": 4, "low": 10, "high": 100},
        {"value": 5, "low": 100, "high": 1000},
    ]

    DEFAULT_VULNERABILITY: List[Dict] = [
        {"value": 1, "low": 0.01, "high": 0.12},
        {"value": 2, "low": 0.12, "high": 0.25},
        {"value": 3, "low": 0.25, "high": 0.5},
        {"value": 4, "low": 0.5, "high": 0.75},
        {"value": 5, "low": 0.75, "high": 1},
    ]

    DEFAULT_CONSEQUENCE: List[Dict] = [
        {"value": 1, "low": 0.0001, "high": 0.005},
        {"value": 2, "low": 0.005, "high": 0.01},
        {"value": 3, "low": 0.01, "high": 0.02},
        {"value": 4, "low": 0.02, "high": 0.05},
        {"value": 5, "low": 0.05, "high": 1},
    ]

    def __init__(self, scales: dict = None):
        if not scales:
            scales = dict()
        self.likelihood_initiation_or_occurence = scales.get(
            "likelihood_initiation_or_occurence", self.DEFAULT_TEF
        )
        self.likelihood_adverse_impact = scales.get(
            "likelihood_adverse_impact", self.DEFAULT_VULNERABILITY
        )
        self.impact = scales.get("impact", self.DEFAULT_CONSEQUENCE)
        self.num_to_text = scales.get("num_to_text", self.DEFAULT_NUM_TO_TEXT)
        self.risk = scales.get("risk", self.DEFAULT_RANGE_TO_TEXT)

    def to_dict(self):
        return {
            "likelihood_initiation_or_occurence": self.likelihood_initiation_or_occurence,
            "likelihood_adverse_impact": self.likelihood_adverse_impact,
            "impact": self.impact,
            "num_to_text": self.num_to_text,
            "risk": self.risk,
        }

    def __hash__(self):
        return hash(freeze(self.to_dict()))

    def __eq__(self, other):
        return self.__hash__() == other.__hash__()

    @classmethod
    def from_dict(cls, scales: dict):
        tmp = QualitativeScale()
        tmp.likelihood_initiation_or_occurence = scales.get(
            "likelihood_initiation_or_occurence", cls.DEFAULT_TEF
        )
        tmp.likelihood_adverse_impact = scales.get(
            "likelihood_adverse_impact", cls.DEFAULT_VULNERABILITY
        )
        tmp.impact = scales.get("impact", cls.DEFAULT_CONSEQUENCE)
        tmp.num_to_text = scales.get("num_to_text", cls.DEFAULT_NUM_TO_TEXT)
        tmp.risk = scales.get("risk", cls.DEFAULT_RANGE_TO_TEXT)
        return tmp

    def get(self, raw, mapping):
        scale = getattr(self, mapping, None)
        num = None
        if not scale:
            raise AttributeError(f"{mapping} does not exist")
        if raw < scale[0].get("low"):
            num = scale[0].get("value")
        elif raw > scale[-1].get("low"):
            num = scale[-1].get("value")
        else:
            for range in scale:
                if range.get("low") <= raw < range.get("high"):
                    num = range.get("value")
        lookup = num
        if not self.num_to_text.get(num):
            lookup = str(num)
        return {"numeric": num, "text": self.num_to_text.get(lookup)}
