#!/usr/bin/env fish

if not set --query HOME
    echo "error: no HOME"
    exit 1
end

set --query XDG_STATE_HOME || set --function XDG_STATE_HOME $HOME/.local/state
set --function nix_state_home $XDG_STATE_HOME/nix
set --function channel_root $nix_state_home/profiles/channels
set --function user_nixpkgs $HOME/.config/nixpkgs
set --function darwin_config /etc/nix-darwin/
set --function nixfiles (path resolve (status dirname)/..)

if set --query XDG_CONFIG_HOME
    set --function hm_config_dir $XDG_CONFIG_HOME/home-manager
else
    set --function hm_config_dir $HOME/.config/home-manager
end

set --function current_script_name (status basename)
for i in 1
    if test ! -d $darwin_config
        if test ! -e $darwin_config && test -L $darwin_config
            echo "$darwin_config is a broken symlink, deleting it [sudo]"
            sudo rm $darwin_config
        end
        echo "darwin configuration folder $darwin_config does not exist, creating it [sudo]"
        sudo mkdir -p $darwin_config
    end
    if test ! -d $user_nixpkgs
        if test ! -e $user_nixpkgs && test -L $user_nixpkgs
            echo "~/.config/nixpkgs is a broken symlink, deleting it"
            rm $user_nixpkgs
        end
        echo "user nixpkgs folder $user_nixpkgs does not exist, creating it"
        mkdir -p $user_nixpkgs
    end
    if test -L $hm_config_dir -a (path resolve $hm_config_dir) = (path resolve (status basename))
        if test y = (read --nchars=1 --prompt-str="$hm_config_dir already exists as a symlink to the current directory. Remove it [yN]? ")
            unlink $hm_config_dir
        end
    end
    if test ! -d $hm_config_dir
        echo "user home-manager configuration folder $hm_config_dir does not exist, creating it"
        mkdir -p $hm_config_dir
    end
    if test ! -e $channel_root
        if test -L $channel_root
            # broken symlink
            rm $channel_root
        end
        echo "channel root $channel_root does not exist, creating it"
        mkdir -p $channel_root
    else
        if test ! -d $channel_root
            echo "error: $channel_root is not a directory"
        else if test -L $channel_root
            echo "error: $channel_root is a symlink, please remove it"
        else if path is --invert --perm write $channel_root
            echo "error: $channel_root is not writable; might be a symlink"
        else if path is --invert --type link $channel_root/*
            for p in (path filter --invert --type link $channel_root/*)
                # might be a broken symlink
                if test -L $p -a ! -e $p
                    rm $p
                else
                    echo "error: channel $p is not a broken symlink, don't know what to do with it"
                end
            end
            # check again and fail if there are still unknown files
            if path is --invert --type link $channel_root/*
                echo "error: non-link(s) in $channel_root"
                path filter --invert --type link $channel_root/*
            else
                continue
            end
        else
            continue # with script
        end
        exit 1
    end
end

set --function current_script_name (status basename)
switch $current_script_name
    case darwin-rebuild
        set --local darwin_config_source $nixfiles/system/$hostname.nix
        set --local darwin_config_target $darwin_config/configuration.nix
        if test ! -e $darwin_config_target
            echo "Need to link $darwin_config_target"
            sudo ln -s $darwin_config_source $darwin_config_target
        end
        set --append argv -I darwin-config=$darwin_config_target
    case nixos-rebuild
        set --local nixos_config_source $nixfiles/system/$hostname.nix
        set --local nixos_config_target $user_nixpkgs/configuration.nix
        if test ! -e $nixos_config_target
            ln -s $nixos_config_source $nixos_config_target
        end
        if ! fish_is_root_user
            set --append argv --use-remote-sudo
        end
        set --append argv -I nixos-config=$nixos_config_source
    case home-manager
        set --local hm_config_source $nixfiles/user/$hostname.nix
        set --export HOME_MANAGER_CONFIG $hm_config_source
end

set --function old_channels (path basename $channel_root/*)

function update_link --argument-names new_src target
    set --function current_src (path resolve $target)
    if test -e $current_src
        if test $current_src = $new_src
            # no need to re-link it
            return
        else
            unlink $target
        end
    end
    ln -s $new_src $target
end

for np in $NIX_PATH
    if string match --quiet --entire "=" $np
        echo $np | read --function --delimiter "=" channel new_src_rel
        set --local new_src (path resolve $new_src_rel)

        if set --local i (contains --index $channel $old_channels)
            set --erase old_channels[$i]
        end

        update_link $new_src $channel_root/$channel
    end
end

for old in $channel_root/$old_channels
    rm $old
end

if set --function i (contains --index (status dirname) $PATH) && test -n $i
    set --erase PATH[$i]
end

set --function cmd $current_script_name $argv

if contains -- -n $argv
    set --prepend cmd echo
end

if set --query IN_NIX_SHELL
    $cmd
else
    nix-shell --run "$cmd"
end