import shutil
import toml


def specific_config(generated_test_configs_root, list_of_schematized_configs, tmp_path):
    """returns a factory function
    that will return the path
    to a specific configuration file, determined by
    characteristics specified by the caller:
    `config_type`, `audio_format`, `spect_format`, `annot_format`

    The factory function actually returns a copy,
    that will be copied into ``tmp_path``,
    so the original remains umodified.

    If ``root_results_dir`` argument is specified
    when calling the factory function,
    it will convert the value for that option in the section
    corresponding to ``config_type`` to the value
    specified for ``root_results_dir``.
    This makes it possible to dynamically change the ``root_results_dir``
    e.g. to the ``tmp_path`` fixture used by unit tests
    """

    def _specific_config(
        config_type,
        model,
        annot_format,
        audio_format=None,
        spect_format=None,
        options_to_change=None,
    ):
        """returns path to a specific configuration file,
        determined by characteristics specified by the caller:
        `config_type`, `audio_format`, `spect_format`, `annot_format`

        Parameters
        ----------
        config_type : str
            corresponding to a `vak` cli command
        annot_format : str
            annotation format, recognized by ``crowsetta``
        audio_format : str
        spect_format : str
        options_to_change : list, dict
            list of dicts with keys 'section', 'option', and 'value'.
            Can be a single dict, in which case only that option is changed.

        Returns
        -------
        config_path : pathlib.Path
            that points to temporary copy of specified config,
            with any options changed as specified
        """
        original_config_path = None

        for schematized_config in list_of_schematized_configs:
            if all(
                [
                    schematized_config["config_type"] == config_type,
                    schematized_config["model"] == model,
                    schematized_config["annot_format"] == annot_format,
                    schematized_config["audio_format"] == audio_format,
                    schematized_config["spect_format"] == spect_format,
                ]
            ):
                original_config_path = generated_test_configs_root.joinpath(
                    schematized_config["filename"]
                )

        if original_config_path is None:
            raise ValueError(
                f"did not find a specific config with `config_type`='{config_type}', "
                f"`annot_format`='{annot_format}', `audio_format`='{audio_format}', "
                f"and `config_type`='{spect_format}', "
            )
        config_copy_path = tmp_path.joinpath(original_config_path.name)
        config_copy_path = shutil.copy(src=original_config_path, dst=config_copy_path)

        if options_to_change is not None:
            if isinstance(options_to_change, dict):
                options_to_change = [options_to_change]
            elif isinstance(options_to_change, list):
                pass
            else:
                raise TypeError(
                    f"invalid type for `options_to_change`: {type(options_to_change)}"
                )

            with config_copy_path.open("r") as fp:
                config_toml = toml.load(fp)

            for opt_dict in options_to_change:
                config_toml[opt_dict["section"]][opt_dict["option"]] = opt_dict["value"]

            with config_copy_path.open("w") as fp:
                toml.dump(config_toml, fp)

        return config_copy_path

    return _specific_config