#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import os.path as osp
import sys


def get_pixi_env_dir():
    if len(sys.argv) >= 2:
        real_me = osp.realpath(sys.argv[1])
    else:
        me = sys.argv[0]
        real_me = osp.dirname(osp.realpath(me))
    pixitoml = osp.join(real_me, 'pixi.toml')
    old_pixitoml = None
    while not osp.exists(pixitoml):
        real_me = osp.dirname(real_me)
        old_pixitoml = pixitoml
        pixitoml = osp.join(real_me, 'pixi.toml')
        if old_pixitoml == pixitoml:
            raise ValueError('could not find pixi environment dir')
    return real_me


def get_bin_dirs(pixi_env_dir):
    src_bin = osp.join(pixi_env_dir, 'build/bin')
    src_bins = [src_bin]
    dev = True
    if not osp.exists(src_bin):
        src_bin = osp.join(pixi_env_dir, '.pixi/envs/default/bin')
        src_bins = [src_bin]
        dev = False
    if dev:
        for comp in ('brainvisa-cmake', 'casa-distro'):
            src_bvm = osp.join(pixi_env_dir, 'src', comp, 'bin')
            if osp.exists(src_bvm):
                src_bins.append(src_bvm)
    return (src_bins, dev)


def get_commands_to_link(src_bin, dev_env):
    exc_cmd = set(['bv', 'bv_pixi', 'bbi-daily'])
    if dev_env:
        return [cmd for cmd in os.listdir(src_bin) if cmd not in exc_cmd]
    prefixs = ['Aims', 'ana', 'si', 'yl', 'Vip', 'bio', 'axon', 'brainvisa',
               'Baby', 'bv_', 'carto', 'casa', 'constel', 'disco',
               'freesurfer', 'morpho', 'qr', 'soma', 'sulci', ]
    exc_prefixs = ['sip', 'sim', 'bv_env']
    cmds = []
    for p in os.listdir(src_bin):
        if p in exc_cmd:
            continue
        for prefix in prefixs:
            if p.startswith(prefix):
                skip = False
                for exc_prefix in exc_prefixs:
                    if p.startswith(exc_prefix):
                        skip = True
                        break
                if not skip:
                    cmds.append(p)
                    break
    return cmds


def remove_dead_links(dst_bin, src_bins):
    for p in os.listdir(dst_bin):
        fullp = osp.join(dst_bin, p)
        if not osp.exists(fullp):
            os.unlink(fullp)
        elif osp.islink(fullp):
            if os.readlink(fullp) == 'bv' \
                    and not any(osp.exists(osp.join(src_bin, p))
                                for src_bin in src_bins):
                # print('remove dead link:', fullp)
                os.unlink(fullp)


def main():
    if '-h' in sys.argv[1:] or '--help' in sys.argv[1:]:
        print('''bv_update_bin_links [env_dir]

    Make symbolic links to BrainVisa executables in the bin/ directory of the
    Pixi/Conda installation directory.

    Executables are then symlinks to the "bv" script, which activates the Pixi
    environment, then calls the executable inside the pixi environment.

    Thus for instance the command "AimsFileInfo file.nii" can be called from
    outside the pixi environment, it will be the same as calling
    "bv AimsFileInfo file.nii".

    The "bv" script will also be installed in the bin/ direcrory of the
    environment.

    The user/developer can safely add the bin/ directory of the pixi
    environment in his/her PATH env variable from his/her .profile or .bashrc
    user config script.

    For a user environment, links to executables found in .pixi/envs/default/
    bin, with appropriate filtering to select only BrainVisa executables, will
    be made. For a developer environment, links to executables found in build/
    bin will be made.

    The environment directory can be specified as an argument to the
    bv_update_bin_links command. If not, it will be searched for, assuming
    that the bv_update_bin_links command is located inside the environment
    directory.
    ''')
        sys.exit(0)

    me = sys.argv[0]
    real_me = osp.dirname(osp.realpath(me))
    pixi_env_dir = get_pixi_env_dir()
    print('pixi dir:', pixi_env_dir)
    src_bins, dev_env = get_bin_dirs(pixi_env_dir)
    dst_bin = osp.join(pixi_env_dir, 'bin')
    if not osp.exists(dst_bin):
        # print('mkdir', dst_bin)
        os.mkdir(dst_bin)

    # bv link
    bv = osp.join(dst_bin, 'bv')
    if not osp.exists(bv) or osp.realpath(bv) != osp.join(real_me, 'bv'):
        bv_link = osp.relpath(osp.join(real_me, 'bv_pixi'), dst_bin)
        # print('bv symlink', bv_link)
        if osp.exists(bv) or osp.islink(bv):
            os.unlink(bv)
        os.symlink(bv_link, bv)

    remove_dead_links(dst_bin, src_bins)

    for src_bin in src_bins:
        cmds = get_commands_to_link(src_bin, dev_env)
        print('cmds:', len(cmds))
        # print(cmds)
        for c in cmds:
            d = osp.join(dst_bin, c)
            if osp.exists(d) or osp.islink(d):
                if os.readlink(d) == 'bv':
                    continue
                os.unlink(d)
            os.symlink('bv', d)


if __name__ == '__main__':
    main()
