import shutil
import mimetypes
import os
from pathlib import Path
from hashlib import md5


class IOFS:
    def __init__(self, ha_enabled=None, ha_file_markers=None):
        # Параметры для Eva HA
        # SPEC https://bcrm.carbonsoft.ru/project/Document/DOC-013742
        self.ha_enabled = ha_enabled
        self.ha_file_markers = ha_file_markers

    def ha_make_symlink(self, src):
        """Создаст маркер для Eva HA (~failover)
        SPEC https://bcrm.carbonsoft.ru/project/Document/DOC-013742

        Args:
            src (str): путь файлу или папке, созданному или изменённому
                       через RDisk
        """
        if self.ha_enabled:
            name = self.io_name(src)
            absolute = self.io_absolute(src)
            digest = md5(absolute.encode("utf-8")).hexdigest()
            link = os.path.join(self.ha_file_markers, f"{digest}.{name}")
            if not self.io_exists(link):
                self.io_mksymlink(absolute, link)

    def io_read_text(self, path):
        with open(path, "r") as file:
            return file.read()
    
    def io_read_bytes(self, path):
        with open(path, "rb") as file:
            return file.read()

    def io_write_text(self, path, data):
        with open(path, "w") as file:
            ret = file.write(data)
        self.ha_make_symlink(path)
        return ret

    def io_write_bytes(self, path, data):
        with open(path, "wb") as file:
            ret = file.write(data)
        self.ha_make_symlink(path)
        return ret
    
    def io_open(self, path, *args, **kwargs):
        return open(path, *args, **kwargs)

    def io_suffix(self, path):
        return Path(path).suffix
    
    def io_suffixes(self, path):
        return Path(path).suffixes

    def io_stem(self, path):
        return Path(path).stem

    def io_absolute(self, path):
        return os.path.abspath(path)

    def io_parts(self, path):
        return Path(path).parts
    
    def io_rename(self, path, target):
        os.rename(path, target)
        self.ha_make_symlink(target)
    
    def io_joinpath(self, path, key):
        return os.path.join(path, *key.split("/"))
    
    def io_parent(self, path):
        return str(Path(path).parent)

    def io_parents(self, path):
        return [str(parent) for parent in Path(path).parents]
    
    def io_name(self, path):
        return Path(path).name

    def io_mkdir(self, path, **kwargs):
        Path(path).mkdir(**kwargs)
        self.ha_make_symlink(path)

    def io_touch(self, path, **kwargs):
        Path(path).touch(**kwargs)
        self.ha_make_symlink(path)

    def io_unlink(self, path, missing_ok=False):
        #  Для обратной совместимости с Python 3.7
        path = Path(path)
        if missing_ok and not path.exists():
            return
        path.unlink()
    
    def io_rmdir(self, path, **kwargs):
        Path(path).rmdir(**kwargs)

    def io_iterdir(self, path):
        for child_path in os.scandir(path):
            yield child_path.path
    
    def io_walk(self, path, top_down=True, on_error=None):
        for entry in os.walk(path, top_down=True, on_error=None):
            yield entry

    def io_is_dir(self, path):
        return Path(path).is_dir()
    
    def io_is_file(self, path):
        return Path(path).is_file()

    def io_exists(self, path):
        return Path(path).exists()

    def io_stat(self, path):
        return Path(path).stat()

    def io_rmtree(self, path):
        shutil.rmtree(path)
    
    def io_copy(self, src, dst):
        shutil.copy(src, dst)
        self.ha_make_symlink(dst)

    def io_mksymlink(self, src, dst):
        Path(dst).symlink_to(src)

    def io_mimetype(self, path):
        mimetypes.add_type('application/vnd.ms-outlook', '.msg')
        mimetypes.add_type('text/plain', '.log')

        mimetype, _ = mimetypes.guess_type(path)
        return mimetype
    
    def io_disk_usage(self, path):
        return shutil.disk_usage(path)
    
    def io_tmp_readonly_path(self, path):
        return self.io_absolute(path)