import os
from abc import ABC, abstractmethod
from typing import Tuple

from smb.common.multiruntime.lib.basics import is_arcadia_python

from .exceptions import InitializationError, OptionNotFound
from .option import Option

if is_arcadia_python:
    from library.python.vault_client.instances import Production as VaultClient
else:
    from vault_client.instances import Production as VaultClient


class BaseAdapter(ABC):
    dependencies: Tuple[Option] = ()

    @abstractmethod
    def load(self, key: str) -> str:
        pass


class OsEnvAdapter(BaseAdapter):
    def load(self, key: str) -> str:
        try:
            return os.environ[key]
        except KeyError:
            raise OptionNotFound(key)


class DotEnvAdapter(BaseAdapter):
    __slots__ = ("content",)

    dependencies = (Option("DOTENV_PATH", default=os.path.join(os.getcwd(), ".env")),)

    content: dict

    def __init__(self, fpath: str):
        self.content = self._parse_file(fpath)

    def load(self, key: str) -> str:
        try:
            return self.content[key]
        except KeyError:
            raise OptionNotFound(key)

    @staticmethod
    def _parse_file(fpath: str) -> dict:
        content = {}

        try:
            with open(fpath, "r") as _f:
                for line in _f.readlines():
                    line = line.strip()

                    if not line or line.startswith("#"):
                        continue

                    key, value = line.split("=", 1)
                    content[key] = value
        except FileNotFoundError:
            raise InitializationError(fpath)

        return content


class YavAdapter(BaseAdapter):
    __slots__ = ("content",)

    dependencies = Option("YAV_TOKEN"), Option("YAV_SECRET_ID")

    content: dict

    def __init__(self, token: str, secret_id):
        client = VaultClient(authorization=token)
        got = client.get_version(secret_id)

        self.content = got["value"]

    def load(self, key: str) -> str:
        try:
            return self.content[key]
        except KeyError:
            raise OptionNotFound(key)
