import json
from typing import List, Any, Dict, Set, Union, Optional

from helpers.file_utils import relative_path

# NOTE: Pwndoc settings have to match up with scan2report.main.text variable's content


class PwndocCustomFields:
    _pwndoc_dict_raw: Optional[dict] = None
    _id_to_label: Dict[str, str] = {}
    _label_to_id: Dict[str, str] = {}
    _label_to_field_info: Dict[str, dict] = {}

    def __init__(self) -> None:
        self.customFields = {}

    def set_field(self, field_name: str, value: Any):
        self.customFields[field_name] = value

    def get_pwndoc_repr(self):
        answer = []
        for x in self.customFields:
            custom_field = self.get_custom_field_by_label(x)
            answer.append({
                "customField": custom_field["_id"],
                "text": self.customFields[x],
            })
        return answer

    # --- STATIC THINGS SAME FOR ALL TEMPLATES ---

    @classmethod
    def __load_list_of_custom_fields(cls, force_refresh=False):
        if force_refresh is False and cls._pwndoc_dict_raw is not None:
            return

        # todo: is force_refresh implemented? It might have gotten skipped due to circular dependency

        cls._id_to_label = {}
        cls._pwndoc_dict_raw = {}

        # The following file is not in repo, it's acquired from Pwndoc via API
        with open(relative_path("api_examples/_api_data_custom-fields.json"), encoding="utf8") as f:
            cls._pwndoc_dict_raw = json.load(f)["datas"]

        custom_fields_for_vulnerabilities = list(filter(lambda x: x["display"] == "vulnerability", cls._pwndoc_dict_raw))

        for custom_field in custom_fields_for_vulnerabilities:
            pwndoc_id = custom_field["_id"]
            label = custom_field["label"]

            assert cls._label_to_id.get(label) is None, f"Duplicate label names ('{label}') are not supported"

            cls._id_to_label[pwndoc_id] = label
            cls._label_to_id[label] = pwndoc_id
            cls._label_to_field_info[label] = custom_field

    @classmethod
    def get_custom_field_by_id(cls, field_id: str) -> dict:
        cls.__load_list_of_custom_fields(force_refresh=False)
        return cls.get_custom_field_by_label(cls._id_to_label.get(field_id, f"NO_LABEL_FOR__{field_id}"))

    @classmethod
    def get_custom_field_by_label(cls, label: str, allow_non_existent: bool = False) -> Optional[dict]:
        cls.__load_list_of_custom_fields(force_refresh=False)

        field = cls._label_to_field_info.get(label)
        if not allow_non_existent:
            assert field, f"Custom field with scan2report name '{label}' doesn't exist"

        return field

    @classmethod
    def get_possible_values_for_select_field(cls, label: str, locale: str) -> List[str]:
        cls.__load_list_of_custom_fields(force_refresh=False)

        raw_options = cls.get_custom_field_by_label(label)["options"]
        options_filtered_by_locale: List[Dict[str, str]] = list(filter(lambda x: x["locale"] == locale, raw_options))
        options_text_only: List[str] = list(map(lambda x: x["value"], options_filtered_by_locale))
        return options_text_only

    @classmethod
    def select_field_pwndoc_to_scan2report(cls, label: str, locale: str, value: str) -> int:
        possible_values = PwndocCustomFields.get_possible_values_for_select_field(label, locale)
        return possible_values.index(value)

    @classmethod
    def select_field_scan2report_to_pwndoc(cls, label: str, locale: str, value: int) -> str:
        possible_values = PwndocCustomFields.get_possible_values_for_select_field(label, locale)
        return possible_values[value]


if __name__ == "__main__":
    example_custom_fields = PwndocCustomFields()
    # print(example_custom_fields.get_possible_values_for_select_field("severity_label", "en"))
    pass
