import json
import os
from typing import Callable
from typing import Dict
from typing import Generic
from typing import Sequence
from typing import Tuple
from typing import TypeVar
from typing import Union


Exists = bool
JsonSerializable = Union[Dict, Sequence, str, bool, int, float]
JsonSerializableGeneric = TypeVar("JsonSerializableGeneric", bound=JsonSerializable)


class DictJsonRepo(Generic[JsonSerializableGeneric]):
    def __init__(self, directory: str = None) -> None:
        self.directory = directory or os.getcwd()

    def read(self, filename: str) -> JsonSerializableGeneric:
        with open(self._build_path(filename), encoding="utf-8") as f:
            return json.load(f)

    def write(self, data: JsonSerializableGeneric, filename: str) -> JsonSerializableGeneric:
        with open(self._build_path(filename), "w", encoding="utf-8") as f:
            json.dump(data, f)

        return data

    def read_or_write_default(
        self, filename: str, default_factory: Callable[[], JsonSerializableGeneric]
    ) -> Tuple[JsonSerializableGeneric, Exists]:
        if os.path.exists(self._build_path(filename)):
            return self.read(filename), True
        else:
            return self.write(default_factory(), filename), False

    def _build_path(self, filename: str) -> str:
        return os.path.join(self.directory, filename)
