# Path: crowd_anki/anki/adapters/anki_deck.py
# class AnkiDeck:
#     _data: dict
# 
#     deck_name_separator = '::'
# 
#     @property
#     def data(self):
#         return self._data
# 
#     @property
#     def is_dynamic(self):
#         return bool(self.data['dyn'])
# 
#     @property
#     def name(self):
#         return self.data['name']
# 
# class NamedLazyDeck(LazyDeck):
#     def __init__(self, name: str, name_initializer: Callable[[str], dict]):
#         super().__init__(lambda: name_initializer(name))
#         self._name = name
# 
#     @property
#     def name(self):
#         return self._name
# 
# Path: crowd_anki/utils/trie.py
# def keys_without_children(trie: Trie):
#     result = []
# 
#     def childless_collector(key_transformer, path, children, _=None):
#         if not list(children):
#             result.append(key_transformer(path))
# 
#     trie.traverse(childless_collector)
#     return result
# 
# Path: crowd_anki/utils/trie.py
# def remove_children_of(trie: Trie, keys):
#     def delete_key(key):
#         del trie[key]
# 
#     seq(keys) \
#         .filter(lambda key: key in trie) \
#         .flat_map(lambda key: trie.keys(prefix=key)) \
#         .filter(lambda key: key not in keys) \
#         .for_each(delete_key)


from abc import ABC, abstractmethod
from dataclasses import dataclass
from functional import seq
from pygtrie import StringTrie
from typing import Iterable, Any
from ..adapters.anki_deck import AnkiDeck, NamedLazyDeck
from ...utils.trie import keys_without_children
from ...utils.trie import remove_children_of
        pass

    @abstractmethod
    def for_names(self, names: Iterable[str]):
        pass

    def decks_by_name(self):
        return {deck.name: deck for deck in self.all()}


@dataclass
class AnkiStaticDeckManager(DeckManager):
    internal_deck_manager: Any

    def all(self) -> Iterable[AnkiDeck]:
        return seq(self.internal_deck_manager.all()) \
            .map(lambda d: AnkiDeck(d)) \
            .filter(lambda d: not d.is_dynamic) \
            .to_list()

    def leaf_decks(self, overrides: Iterable[AnkiDeck] = tuple()) -> Iterable[AnkiDeck]:
        deck_trie = self.deck_trie()
        override_keys = [deck.name for deck in overrides]

        remove_children_of(deck_trie, override_keys)
        keys = keys_without_children(deck_trie)

        return [deck_trie[key] for key in keys]

    def deck_trie(self):

# Path: crowd_anki/anki/adapters/anki_deck.py
# class AnkiDeck:
#     _data: dict
# 
#     deck_name_separator = '::'
# 
#     @property
#     def data(self):
#         return self._data
# 
#     @property
#     def is_dynamic(self):
#         return bool(self.data['dyn'])
# 
#     @property
#     def name(self):
#         return self.data['name']
# 
# class NamedLazyDeck(LazyDeck):
#     def __init__(self, name: str, name_initializer: Callable[[str], dict]):
#         super().__init__(lambda: name_initializer(name))
#         self._name = name
# 
#     @property
#     def name(self):
#         return self._name
# 
# Path: crowd_anki/utils/trie.py
# def keys_without_children(trie: Trie):
#     result = []
# 
#     def childless_collector(key_transformer, path, children, _=None):
#         if not list(children):
#             result.append(key_transformer(path))
# 
#     trie.traverse(childless_collector)
#     return result
# 
# Path: crowd_anki/utils/trie.py
# def remove_children_of(trie: Trie, keys):
#     def delete_key(key):
#         del trie[key]
# 
#     seq(keys) \
#         .filter(lambda key: key in trie) \
#         .flat_map(lambda key: trie.keys(prefix=key)) \
#         .filter(lambda key: key not in keys) \
#         .for_each(delete_key)


# Path: crowd_anki/anki/adapters/deck_manager.py
from abc import ABC, abstractmethod
from dataclasses import dataclass
from functional import seq
from pygtrie import StringTrie
from typing import Iterable, Any
from ..adapters.anki_deck import AnkiDeck, NamedLazyDeck
from ...utils.trie import keys_without_children
from ...utils.trie import remove_children_of

        pass

    @abstractmethod
    def for_names(self, names: Iterable[str]):
        pass

    def decks_by_name(self):
        return {deck.name: deck for deck in self.all()}


@dataclass
class AnkiStaticDeckManager(DeckManager):
    internal_deck_manager: Any

    def all(self) -> Iterable[AnkiDeck]:
        return seq(self.internal_deck_manager.all()) \
            .map(lambda d: AnkiDeck(d)) \
            .filter(lambda d: not d.is_dynamic) \
            .to_list()

    def leaf_decks(self, overrides: Iterable[AnkiDeck] = tuple()) -> Iterable[AnkiDeck]:
        deck_trie = self.deck_trie()
        override_keys = [deck.name for deck in overrides]

        remove_children_of(deck_trie, override_keys)
        keys = keys_without_children(deck_trie)

        return [deck_trie[key] for key in keys]

    def deck_trie(self):

        return StringTrie(**self.decks_by_name(), separator=AnkiDeck.deck_name_separator)