from __future__ import annotations
from typing import Union, Dict, List, Any
from datetime import datetime, timedelta
import os
import tempfile
from contextlib import contextmanager
import logging
from collections import Counter

import yaml

logger = logging.getLogger(__name__)


class Yammler(dict):
    _no_dump = ["changed"]
    _metavars = ["fspath", "updated_at"]
    _data_key = "data"
    _meta_key = "meta"

    def __init__(self, fspath: str, data: dict = None):
        self.fspath = fspath
        self.changed = False
        self.updated_at = self.stamp()
        data = {}
        if os.path.exists(fspath):
            with open(fspath) as f:
                data = yaml.safe_load(f) or {}
        super().__init__(data)

    def dump(self) -> None:
        with self.durable(self.fspath, "w") as f:
            yaml.safe_dump(dict(self), f, default_flow_style=False)

    @staticmethod
    def stamp():
        return datetime.utcnow()

    @classmethod
    @contextmanager
    def context(cls, fspath):
        obj = cls(fspath)
        try:
            yield obj
        finally:
            obj.dump(force=True)

    @classmethod
    @contextmanager
    def durable(cls, fspath: str, mode: str = "w+b"):
        """ Safely write to file """
        _fspath = fspath
        _mode = mode
        _file = tempfile.NamedTemporaryFile(_mode, delete=False)

        try:
            yield _file
        except Exception as e:  # noqa
            os.unlink(_file.name)
            raise e
        else:
            _file.close()
            os.rename(_file.name, _fspath)

