import os
import sys
import glob
import shutil
import setuptools.command.develop as develop

"""
This module contains some little workaround for the problem that
`python setup.py develop` (and thus `pip install -e .`) is incompatible
with a package layout where the modules are living on the top level.
However, that top-level-layout is needed for backward compatibility.
"""

current_dir = os.path.dirname(os.path.abspath(sys.modules.get(__name__).__file__))
parent_dir = os.path.dirname(current_dir)


def install_develop_mode(dist):
    """
    `python setup.py develop` assumes a directory structure where the package
    to be installed lives in a subdirectory. This function assumes that this command
    has already been run. Now it remains to
        - adapt the path inside the <package_name>.egg-link-text file (-> parent_dir)
        - adapt the path inside easy_install.pth (-> parent_dir)
        - move the directory <package_name>.egg-info to parent_dir

    For safety reasons the following directory structure is assumed:

    <arbitrary_dir_name>/              <- the .egg-link will point here
    │
    ├── <package_name>/                <- all the source lives here
    │   ├── .git/
    │   ├── setup.py
    │   ├── setup_develop_mode.py
    │   └── ...
    └── <package_name.egg-info>/       <- autogenerated by setuptools, moved here by this function

    Note: No other directories or files are allowed inside <arbitrary_dir_name>.

    :param dist: setuptools.dist object
    :return:
    """
    # noinspection PyArgumentList
    dev_obj = develop.develop(dist)
    dev_obj.ensure_finalized()
    old_egg_path = dev_obj.egg_path
    new_egg_path = os.path.dirname(old_egg_path)

    # ensure the required directory structure is met
    sibling_dirs = glob.glob(os.path.join(parent_dir, "*"))

    # remove the trivial case:
    sibling_dirs.remove(current_dir)

    # allow egg-info dir from previous install (will be overwritten anyway)
    parent_egg_info = os.path.join(parent_dir, os.path.split(dev_obj.dist.egg_info)[1])
    if parent_egg_info in sibling_dirs:
        sibling_dirs.remove(parent_egg_info)

    if len(sibling_dirs) > 0:
        # maybe it would be convenient to allow some exceptions here like, e.g. for config files
        msg = "The following files/directories contradict the assumed directory structure:\n{}"
        msg = msg.format("\n".join(sibling_dirs))
        raise FileExistsError(msg)

    if dev_obj.dry_run:
        return

    # this heavily inspired by setuptools.commands.develop.develop.install_for_development
    with open(dev_obj.egg_link, "w") as f:
        f.write(new_egg_path + "\n" + dev_obj.setup_path)

    # now move the egg-info directory one level higher
    egg_info_dirs = glob.glob(os.path.join(current_dir, "*egg-info"))
    assert len(egg_info_dirs) == 1
    source = egg_info_dirs[0]
    target = os.path.join(parent_dir, os.path.split(source)[1])
    assert target == parent_egg_info

    shutil.rmtree(target, ignore_errors=True)
    shutil.move(source, target)

    # this is inspired by pip._internals.req.req_uninstall.UninstallPathSet.from_dist
    easy_install_pth = os.path.join(os.path.dirname(dev_obj.egg_link), 'easy-install.pth')

    with open(easy_install_pth, "r") as f:
        all_paths = f.read()

    if old_egg_path in all_paths:
        all_paths = all_paths.replace(old_egg_path, new_egg_path)
        with open(easy_install_pth, "w") as f:
            f.write(all_paths)
