from typing import Optional
import uuid

from helpers.custom_logging import FlashLog
from helpers.file_utils import relative_path, json_dump, json_safe_load
from flask import abort, Response

GROUPS_FILE_PATH = relative_path("scan2report/plugins/groups.json")
ALIAS_FILE_PATH = relative_path("scan2report/plugins/aliases.json")


class TemplateAliasing:
    alias_data: dict = {}

    @classmethod
    def refresh(cls):
        cls.alias_data = cls._load_alias_data()
        return cls.alias_data

    @staticmethod
    def _load_alias_data() -> dict:
        alias_data = json_safe_load(ALIAS_FILE_PATH)
        if alias_data is None:
            FlashLog.error("Alias file doesn't exist or is invalid JSON. Manual fix is needed.")
            abort(500)
        return alias_data

    @classmethod
    def is_fid_alias(cls, fid: str):
        alias_names = cls.alias_data.keys()

        if len(set(alias_names)) != len(alias_names):
            FlashLog.warning("Alias files contains duplicate names. Manual fix is needed.")

        return fid in alias_names

    @classmethod
    def get_alias(cls, fid: str) -> Optional[str]:
        for alias_id, fids in cls.alias_data.items():
            if fid in fids:
                return alias_id
        return


def _extract_gid(group_struct: dict) -> Optional[str]:
    return group_struct.get("gid")


class TemplateGrouping:
    group_data: dict = {}

    @staticmethod
    def _load_group_data() -> dict:
        group_data = json_safe_load(GROUPS_FILE_PATH)
        if group_data is None:
            FlashLog.error("Plugins file doesn't exist or is invalid JSON. Manual fix is needed.")
            abort(500)
        return group_data

    @classmethod
    def refresh(cls):
        cls.group_data = cls._load_group_data()
        return cls.group_data

    @classmethod
    def is_gid(cls, fid: str):
        gids = [_extract_gid(x) for x in cls.group_data]
        return fid in gids

    @classmethod
    def get_gid(cls, fid: str) -> Optional[str]:
        for single_group in cls.group_data:
            fids = [x.get("id") for x in single_group.get("plugins", [])]
            if fid in fids:
                return _extract_gid(single_group)
        return

    @classmethod
    def add_new_gids(cls):
        group_data = cls.refresh()

        existing_gids = set()
        for single_group in group_data:
            current_gid = _extract_gid(single_group)
            if current_gid:
                if current_gid in existing_gids:
                    FlashLog.warning(f"Duplicate GID ({current_gid}) detected. Fix it manually.")  # todo: this doesn't flash, only logs
                existing_gids.add(current_gid)

        for single_group in group_data:
            if _extract_gid(single_group):
                continue
            gid = single_group["name"]["en"]
            gid = gid.encode("ascii", "ignore").decode()
            gid = gid.replace(" ", "_")
            gid = gid[:50]

            # GID shouldn't be duplicate, so rather add random suffix if necessary
            random_suffix = ""
            while (gid + random_suffix) in existing_gids:
                random_suffix = "_" + str(uuid.uuid4())[:8]

            single_group["gid"] = gid + random_suffix

        json_dump(group_data, GROUPS_FILE_PATH)  # todo: compact JSON print here would be better readable
        cls.refresh()
