#
#   Copyright © 2021,2022 IsardVDI S.L.
#   Copyright © 2022 Evilham <contact@evilham.com>
#
#   This file is part of DD
#
#   DD is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or (at your
#   option) any later version.
#
#   DD is distributed in the hope that it will be useful, but WITHOUT ANY
#   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#   FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
#   details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import random
import string
from collections import Counter
from pprint import pprint

from typing import Any, Dict, Generator, Iterable, Optional, List

DDGroup = Dict[str, Any]

def get_recursive_groups(l_groups : Iterable[DDGroup], l : List[DDGroup]) -> List[DDGroup]:
    for d_group in l_groups:
        data = {}
        for key, value in d_group.items():
            if key == "subGroups":
                get_recursive_groups(value, l)
            else:
                data[key] = value
        l.append(data)
    return l


def get_group_with_childs(keycloak_group : DDGroup) -> List[str]:
    return [g["path"] for g in get_recursive_groups([keycloak_group], [])]


def system_username(username : str) -> bool:
    return (
        True
        if username in ["guest", "ddadmin", "admin"] or username.startswith("system_")
        else False
    )


def system_group(groupname : str) -> bool:
    return True if groupname in ["admin", "manager", "teacher", "student"] else False


def get_group_from_group_id(group_id : str, groups : Iterable[DDGroup]) -> Optional[DDGroup]:
    return next((d for d in groups if d.get("id") == group_id), None)


def get_kid_from_kpath(kpath : str, groups : Iterable[DDGroup]) -> Optional[str]:
    ids : List[str] = [g["id"] for g in groups if g["path"] == kpath]
    if len(ids) != 1:
        return None
    return ids[0]


def get_gid_from_kgroup_id(kgroup_id : str, groups : Iterable[DDGroup]) -> str:
    # TODO: Why is this interface different from get_kid_from_kpath?
    o : List[str] = [
        g["path"].replace("/", ".")[1:] if len(g["path"].split("/")) else g["path"][1:]
        for g in groups
        if g["id"] == kgroup_id
    ]
    return o[0]


def get_gids_from_kgroup_ids(kgroup_ids : Iterable[str], groups : Iterable[DDGroup]) -> List[str]:
    return [get_gid_from_kgroup_id(kgroup_id, groups) for kgroup_id in kgroup_ids]


def kpath2gid(path : str) -> str:
    # print(path.replace('/','.')[1:])
    if path.startswith("/"):
        return path.replace("/", ".")[1:]
    return path.replace("/", ".")


def kpath2gids(path : str) -> List[str]:
    path = kpath2gid(path)
    l = []
    for i in range(len(path.split("."))):
        l.append(".".join(path.split(".")[: i + 1]))
    return l


def kpath2kpaths(path : str) -> List[str]:
    l = []
    for i in range(len(path.split("/"))):
        l.append("/".join(path.split("/")[: i + 1]))
    return l[1:]


def gid2kpath(gid : str) -> str:
    return "/" + gid.replace(".", "/")


def count_repeated(itemslist : Iterable[Any]) -> None:
    print(Counter(itemslist))


def groups_kname2gid(groups : Iterable[str]) -> List[str]:
    return [name.replace(".", "/") for name in groups]


def groups_path2id(groups : Iterable[str]) -> List[str]:
    return [g.replace("/", ".")[1:] for g in groups]


def groups_id2path(groups : Iterable[str]) -> List[str]:
    return ["/" + g.replace(".", "/") for g in groups]


def filter_roles_list(role_list : Iterable[str]) -> List[str]:
    client_roles = ["admin", "manager", "teacher", "student"]
    return [r for r in role_list if r in client_roles]


def filter_roles_listofdicts(role_listofdicts : Iterable[Dict[str, Any]]) -> List[Dict[str, Any]]:
    client_roles = ["admin", "manager", "teacher", "student"]
    return [r for r in role_listofdicts if r["name"] in client_roles]


def rand_password(lenght : int) -> str:
    # TODO: why is this not using py3's secrets?
    characters = string.ascii_letters + string.digits + string.punctuation
    passwd = "".join(random.choice(characters) for i in range(lenght))
    while not any(ele.isupper() for ele in passwd):
        passwd = "".join(random.choice(characters) for i in range(lenght))
    return passwd
