from __future__ import annotations
from io import TextIOWrapper
from typing import Callable, TypeAlias


FileParser: TypeAlias = Callable[[TextIOWrapper], dict[str, str]]


def load_data(obj, file_parser: FileParser, extensions: tuple[str, ...], **kwargs):
    """
    Utility to load data to dynaconf settings from files that match `extensions` using custom file_reader
    :obj: the obj provided by `load()` (a settings instance)
    :param file_parser: a function that receives a file stream and return it's content as a dict
    :extensions: the extensions used to select which files will be read.
    """

    if filename := kwargs.get("filename"):
        with open(filename) as open_file:
            data = file_parser(open_file)
            obj.update(data)
            obj._loaded_files.append(filename)
    else:

        # get all filenames with given extension
        all_files = obj.settings_file or obj.settings_files
        sff_files = [file for file in all_files if file.endswith(extensions)]

        # read all selected files
        for file in all_files:
            with open(file) as open_file:
                data = file_parser(open_file)
                obj.update(data)
                obj._loaded_files.append(file)


def load(obj, *args, **kwargs):
    """
    Reads and loads in to "obj" a single key or all keys from source
    :param obj: the settings instance
    :param env: settings current env (upper case) default='DEVELOPMENT'
    :param silent: if errors should raise
    :param key: if defined load a single key, else load all from `env`
    :param filename: Custom filename to load (useful for tests)
    :return: None
    """
    # Load data from your custom data source (file, database, memory etc)
    # use `obj.set(key, value)` or `obj.update(dict)` to load data
    # use `obj.find_file('filename.ext')` to find the file in search tree
    # Return nothing

    # This loader reads the .sff file // Stupid File Format

    SFF_EXTENSIONS = (".sff", ".sfx")

    def file_parser(file: TextIOWrapper):
        """Should be implemented by the user to parse his own filetype"""
        keys = []
        values = []
        for line in file.readlines():
            if line.startswith("#"):
                continue
            if line.startswith("KEYS:"):
                keys = line.strip("KEYS:").strip("\n").split(";")
            if line.startswith("VALUES:"):
                values = line.strip("VALUES:").strip("\n").split(";")
        return dict(zip(keys, values))

    load_data(obj, file_parser, SFF_EXTENSIONS, **kwargs)