#!/usr/bin/env bash
: <<!
------------------------------------------------------------------------------
  Yazi nicotine plugin — using external nicotine bash script patched to create
  a single repo from multiple selected files.
  Requires: httm, git, tar, find, stat, realpath (or readlink -f), mktemp
 ------------------------------------------------------------------------------
!

DEST=${1:-/etc/skel/}

YAZI_HOME="${DEST}/.config/yazi"
YAZI_PLUGIN_HOME="${YAZI_HOME}/plugins"
NICOTINE_PLUGIN_HOME="${YAZI_PLUGIN_HOME}/nicotine.yazi"

mkdir -p "${NICOTINE_PLUGIN_HOME}"

conf_print_nicotine_main() {
  cat <<'EOF'
local DEBUG_MODE = true

local function log(message)
    if DEBUG_MODE then
        ya.err(string.format("[Nicotine Debug] %s", message))
    end
end

-- 1. Grab current state (Sync to access cx)
local setup = ya.sync(function()
    local targets = {}
    local selected = cx.active.selected
    if #selected == 0 then
        local hovered = cx.active.current.hovered
        if hovered then
            table.insert(targets, tostring(hovered.url))
        end
    else
        for _, item in pairs(selected) do
            table.insert(targets, tostring(item.url))
        end
    end
    return {
        targets = targets,
        cwd = tostring(cx.active.current.cwd)
    }
end)

return {
    entry = function(self, args)
        log("Plugin started")
        
        local state = setup() 
        local targets = state.targets
        local cwd = state.cwd

        if #targets == 0 then
            return ya.notify({ title = "Nicotine", content = "No files selected", level = "warn" })
        end

        local is_archive = args[1] == "--archive"
        
        -- Create a unique temp container
        local tmp_container = string.format("%s/yazi-nicotine-%d", os.getenv("TMPDIR") or "/tmp", math.random(100000, 999999))
        
        local status = Command("mkdir"):arg("-p"):arg(tmp_container):spawn():wait()
        if not status or not status.success then
            return ya.notify({ title = "Nicotine", content = "Failed to create temp dir", level = "error" })
        end

        ya.notify({ 
            title = "Nicotine", 
            content = is_archive and "Creating archive..." or "Generating Git history...", 
            timeout = 2 
        })

        -- Build Nicotine Command
        -- Note: using --single-repo as seen in your test script to ensure one combined git
        local cmd = Command("nicotine")
        cmd:arg("--output-dir"):arg(tmp_container)
        cmd:arg("--single-repo")
        
        if not is_archive then 
            cmd:arg("--no-archive") 
        end

        for _, path in ipairs(targets) do
            cmd:arg(path)
        end

        local nicotine_status = cmd:spawn():wait()

        if not nicotine_status or not nicotine_status.success then
            Command("rm"):arg("-rf"):arg(tmp_container):spawn():wait()
            return ya.notify({ title = "Nicotine Error", content = "Nicotine execution failed.", level = "error" })
        end

        -- Path fix: nicotine creates a sub-directory
        local repo_path = tmp_container .. "/nicotine-combined-git"

        if is_archive then
            local archive_src = tmp_container .. "/nicotine-combined-git.tar.gz"
            local status = Command("cp")
                :arg(archive_src)
                :arg(cwd)
                :spawn()
                :wait()
            if not status or not status.success then
              ya.notify({ title = "Nicotine", content = "Failed to copy archive", level = "error" })
              return
            end
            ya.notify({ title = "Nicotine", content = "Archive copied to current directory", timeout = 3 })
        else
            -- Git/Lazygit Section
            local permit = ui.hide()
            local child_status = Command("lazygit")
                :cwd(repo_path) -- Enter the actual git directory
                :stdin(Command.INHERIT)
                :stdout(Command.INHERIT)
                :stderr(Command.INHERIT)
                :spawn()
                :wait()
            permit:drop()
        end

        -- Cleanup container
        Command("rm"):arg("-rf"):arg(tmp_container):spawn():wait()
        
        if not is_archive then
            ya.notify({ title = "Nicotine", content = "Session complete.", timeout = 2 })
        end
    end
}
EOF
}
conf_print_nicotine_main | tee "${NICOTINE_PLUGIN_HOME}/main.lua"

#----------------------------------------------------------------

conf_print_nicotine_keymap() {
  cat <<'EOF'
[[mgr.prepend_keymap]]
on   = [ "g", "n" ]
run  = "plugin nicotine"
desc = "Run Nicotine Git snapshot history (lazygit)"

[[mgr.prepend_keymap]]
on   = [ "g", "z" ]
run  = "plugin nicotine --args='--archive'"
desc = "Create compressed Nicotine archive of selection"
EOF
}
# conf_print_nicotine_keymap | tee -a "${YAZI_HOME}/keymap.toml"

#----------------------------------------------------------------

# Create a version of nicotine that has the --single-repo option.
conf_print_nicotine_script() {
  cat <<'EOF'
#!/usr/bin/env bash

set -euf -o pipefail
#set -x

print_version() {
    printf "\
  nicotine $(httm --version | cut -f2 -d' ')
  " 1>&2
    exit 0
}

print_usage() {
    local nicotine="\e[31mnicotine\e[0m"
    local httm="\e[31mhttm\e[0m"
    local git="\e[31mgit\e[0m"
    local tar="\e[31mtar\e[0m"

    printf "\
$nicotine is a wrapper script for $httm which converts unique snapshot file versions to a $git archive.

USAGE:
    nicotine [OPTIONS]... [file1 file2...]

OPTIONS:
    --output-dir:
        Select the output directory. Default is current working directory.
    --no-archive
        Disable archive creation. Create a new $git repository.
    --single-repo:
        Add all provided files/dirs into a single git repository instead of one per argument.
    --debug:
        Show $git and $tar command output.
    --help:
        Display this dialog.
    --version:
        Display script version.

" 1>&2
    exit 1
}

prep_exec() {
    for cmd in find readlink git tar mktemp mkdir httm; do
        command -v "$cmd" >/dev/null 2>&1 || { printf "Error: '$cmd' is required.\n" 1>&2; exit 1; }
    done
}

function copy_add_commit {
    local debug=$1; shift
    local path="$1"; shift
    local dest_dir="$1"; shift

    if [[ -d "$path" ]]; then 
        cp -a "$path" "$dest_dir/"
        return 0
    else
        cp -a "$path" "$dest_dir"
    fi

    local commit_date
    commit_date=$(date -d "$(stat -c %y "$path")")

    if [[ "$debug" = true ]]; then
        git add --all "$dest_dir"
        git commit -m "httm commit from ZFS snapshot: $(basename "$path")" --date "$commit_date" || true
    else
        git add --all "$dest_dir" > /dev/null
        git commit -q -m "httm commit from ZFS snapshot: $(basename "$path")" --date "$commit_date" > /dev/null || true
    fi
}

function get_unique_versions {
    local debug=$1; shift
    local path="$1"; shift
    local dest_dir="$1"; shift

    local -a version_list=()
    if [[ ! -d "$path" ]]; then
        while read -r line; do
            [[ -n "$line" ]] && version_list+=("$line")
        done <<<"$(httm -n --omit-ditto "$path")"
    fi

    if [[ -d "$path" ]] || [[ ${#version_list[@]} -le 1 ]]; then
        copy_add_commit "$debug" "$path" "$dest_dir"
    else
        for version in "${version_list[@]}"; do
            copy_add_commit "$debug" "$version" "$dest_dir"
        done
    fi
}

function traverse {
    local debug=$1; shift
    local path="$1"; shift
    local dest_dir="$1"; shift

    get_unique_versions "$debug" "$path" "$dest_dir"
    [[ -d "$path" ]] || return 0

    local basename
    basename=$(basename "$path")
    
    while read -r entry; do
        [[ -z "$entry" ]] && continue
        if [[ -d "$entry" ]]; then
            traverse "$debug" "$entry" "$dest_dir/$basename"
        else
            get_unique_versions "$debug" "$entry" "$dest_dir/$basename"
        fi
    done <<<"$(find "$path" -mindepth 1 -maxdepth 1)"
}

function nicotine {
  (
    prep_exec

    local debug=false
    local no_archive=false
    local single_repo=false
    local output_dir="$(pwd)"
    local -a input_files=()

    while [[ $# -ge 1 ]]; do
        case "$1" in
            --output-dir) shift; output_dir="$(realpath "$1")"; shift ;;
            --debug) debug=true; shift ;;
            --no-archive) no_archive=true; shift ;;
            --single-repo) single_repo=true; shift ;;
            --help|-h) print_usage ;;
            --version|-V) print_version ;;
            *) input_files+=("$1"); shift ;;
        esac
    done

    [[ ${#input_files[@]} -gt 0 ]] || { printf "Error: No input files.\n" 1>&2; exit 1; }

    local tmp_dir
    tmp_dir="$(mktemp -d)"
    trap 'rm -rf "$tmp_dir"' EXIT

    if [[ "$single_repo" = true ]]; then
        local repo_name="nicotine-combined"
        local archive_dir="$tmp_dir/$repo_name"
        mkdir -p "$archive_dir"
        cd "$archive_dir"
        git init -q

        for file in "${input_files[@]}"; do
            local can_path
            can_path=$(realpath "$file" 2>/dev/null) || continue
            [[ -e "$can_path" ]] || continue
            
            # if [[ -d "$can_path" ]]; then
            #     traverse "$debug" "$can_path" "$tmp_dir"
            # else
            #     traverse "$debug" "$can_path" "$archive_dir"
            # fi

            traverse "$debug" "$can_path" "$archive_dir"
        done

        finalize_output "$debug" "$no_archive" "$tmp_dir" "$output_dir" "$repo_name"
    else
        for file in "${input_files[@]}"; do
            local can_path
            can_path=$(realpath "$file" 2>/dev/null) || continue
            [[ -e "$can_path" ]] || continue
            
            local base
            base=$(basename "$can_path")
            base="${base#.}"
            
            local archive_dir="$tmp_dir/$base"
            mkdir -p "$archive_dir"
            (
                cd "$archive_dir"
                git init -q
  #
                # if [[ -d "$can_path" ]]; then
                #     traverse "$debug" "$can_path" "$tmp_dir"
                # else
                #     traverse "$debug" "$can_path" "$archive_dir"
                # fi

                traverse "$debug" "$can_path" "$archive_dir"
            )
            finalize_output "$debug" "$no_archive" "$tmp_dir" "$output_dir" "$base"
            rm -rf "${archive_dir:?}"
        done
    fi
  )
}

function finalize_output {
    local debug=$1 no_archive=$2 tmp=$3 out=$4 base=$5
    if [[ "$no_archive" = true ]]; then
        cp -ra "$tmp/$base" "$out/$base-git"
        printf "Repository created: $out/$base-git\n"
    else
        local out_file="$out/$base-git.tar.gz"
        tar -C "$tmp" -zcf "$out_file" "$base"
        printf "Archive created: $out_file\n"
    fi
}

nicotine "${@}"
EOF
}
# So as to not loose the original nicotine bash script.
if [[ -f /usr/bin/nicotine ]]; then
  if [[ -f /usr/bin/nicotine.bak ]]; then
    sudo mv /usr/bin/nicotine.bak /usr/bin/nicotine
  fi
  sudo mv /usr/bin/nicotine /usr/bin/nicotine.bak
  conf_print_nicotine_script | sudo tee /usr/bin/nicotine
  sudo chmod +x /usr/bin/nicotine
fi
