from abc import ABCMeta, abstractmethod
from typing import Iterator, Optional, Union
from uuid import UUID


class Vault(metaclass=ABCMeta):
    def __init__(self, name: str, no_push: bool = False):
        self.name = name
        self.no_push = no_push

    def __str__(self) -> str:
        return f"{self.name} {type(self).__name__}"

    @abstractmethod
    def get_key(self, kid: Union[UUID, str], service: str) -> Optional[str]:
        """
        Get Key from Vault by KID (Key ID) and Service.

        It does not get Key by PSSH as the PSSH can be different depending on it's implementation,
        or even how it was crafted. Some PSSH values may also actually be a CENC Header rather
        than a PSSH MP4 Box too, which makes the value even more confusingly different.

        However, the KID never changes unless the video file itself has changed too, meaning the
        key for the presumed-matching KID wouldn't work, further proving matching by KID is
        superior.
        """

    @abstractmethod
    def get_keys(self, service: str) -> Iterator[tuple[str, str]]:
        """Get All Keys from Vault by Service."""

    @abstractmethod
    def add_key(self, service: str, kid: Union[UUID, str], key: str) -> bool:
        """Add KID:KEY to the Vault."""

    @abstractmethod
    def add_keys(self, service: str, kid_keys: dict[Union[UUID, str], str]) -> int:
        """
        Add Multiple Content Keys with Key IDs for Service to the Vault.
        Pre-existing Content Keys are ignored/skipped.
        Raises PermissionError if the user has no permission to create the table.
        """

    @abstractmethod
    def get_services(self) -> Iterator[str]:
        """Get a list of Service Tags from Vault."""


__all__ = ("Vault",)
