#!/usr/bin/env fish

set -g VERSION "1.0.1"
set -g SCRIPT_DIR (realpath (status dirname))
set -g DEFAULT_RULE "$GDIFF_DEFAULT_RULE"
if test -z "$DEFAULT_RULE"
    set -g DEFAULT_RULE "/usr/share/gdiff/rule.txt"
    if not test -f "$DEFAULT_RULE"; and test -f "$SCRIPT_DIR/../share/rule.txt"
        set -g DEFAULT_RULE "$SCRIPT_DIR/../share/rule.txt"
    end
end
set -g config_home "$XDG_CONFIG_HOME"
if test -z "$config_home"
    set -g config_home "$HOME/.config"
end
set -g USER_RULE_TXT "$config_home/gdiff/rule.txt"
set -g USER_RULE_MD "$config_home/gdiff/rule.md"

set -g RED (set_color red)
set -g GREEN (set_color green)
set -g BOLD (set_color --bold)
set -g RESET (set_color normal)

function detect_clipboard
    if type -q wl-copy; and test -n "$WAYLAND_DISPLAY"
        echo "wl-copy"
    else if type -q xclip; and test -n "$DISPLAY"
        echo "xclip -selection clipboard"
    else if type -q xsel; and test -n "$DISPLAY"
        echo "xsel --clipboard --input"
    else if type -q pbcopy
        echo "pbcopy"
    else if type -q clip.exe
        echo "clip.exe"
    else
        echo ""
    end
end

function show_help
    echo "$BOLD"USAGE"$RESET"
    echo "  gdiff [OPTIONS]"
    echo ""
    echo "$BOLD"OPTIONS"$RESET"
    echo "  -r, --rule <file>   Use a custom rule file (.txt or .md)"
    echo "  -p, --print         Print the output instead of copying to clipboard"
    echo "  -d, --diff-only     Copy only the diff, without the rule"
    echo "  --restore-rule      Restore default rule to ~/.config/gdiff/rule.txt"
    echo "  --rule-path         Show which rule file is being used"
    echo "  -v, --version       Show version"
    echo "  -h, --help          Show this help"
    echo ""
    echo "$BOLD"RULE PRECEDENCE"$RESET"
    echo "  1. --rule <file>                 (highest)"
    echo "  2. ~/.config/gdiff/rule.txt"
    echo "  3. /usr/share/gdiff/rule.txt     (default)"
end

function do_restore_rule
    set -l config_dir "$config_home/gdiff"
    set -l config_file "$config_dir/rule.txt"

    if not test -f "$DEFAULT_RULE"
        echo "$RED"Error:"$RESET Default rule not found at $DEFAULT_RULE" >&2
        return 1
    end

    if test -f "$config_file"
        set -l prompt_str (printf "%sWarning:%s A rule file already exists at %s. Overwrite? (y/N): " "$RED" "$RESET" "$config_file")
        read -l response -P "$prompt_str"
        switch "$response"
            case 'y' 'Y' 'yes' 'YES' 'Yes'

            case '*'
                echo "Operation cancelled."
                return 0
        end
    end

    mkdir -p "$config_dir"
    cp "$DEFAULT_RULE" "$config_file"
    echo "$GREEN"✓"$RESET Restored default rule to $config_file (from $DEFAULT_RULE)"
end

function resolve_rule
    set -l custom_rule "$argv[1]"

    if test -n "$custom_rule"
        if not test -f "$custom_rule"
            echo "$RED"Error:"$RESET Rule file not found: $custom_rule" >&2
            exit 1
        end
        echo "$custom_rule"
        return
    end

    # If running from the development repository, prioritize repo's share/rule.txt
    if test -e "$SCRIPT_DIR/../.git"; and test -f "$SCRIPT_DIR/../share/rule.txt"
        echo "$SCRIPT_DIR/../share/rule.txt"
        return
    end

    if test -f "$USER_RULE_TXT"
        echo "$USER_RULE_TXT"
        return
    end

    if test -f "$USER_RULE_MD"
        echo "$USER_RULE_MD"
        return
    end

    if test -f "$DEFAULT_RULE"
        echo "$DEFAULT_RULE"
        return
    end

    echo "$RED"Error:"$RESET No rule file found. Run 'gdiff --restore-rule' to create one." >&2
    exit 1
end

function lazy_init
    set -l config_dir "$config_home/gdiff"
    set -l config_file "$config_dir/rule.txt"
    set -l config_file_md "$config_dir/rule.md"

    if not test -f "$config_file"; and not test -f "$config_file_md"; and test -f "$DEFAULT_RULE"
        mkdir -p "$config_dir"
        cp "$DEFAULT_RULE" "$config_file"
    end
end

function stream_content
    set -l rule_file "$argv[1]"
    git diff --cached --stat
    echo
    git diff --cached
    echo
    echo
    if test -n "$rule_file"
        cat "$rule_file"
    end
end

function main
    set -l custom_rule ""
    set -l print_only false
    set -l show_rule_path false
    set -l diff_only false

    set -l i 1
    while test $i -le (count $argv)
        switch $argv[$i]
            case -r --rule
                set -l next_i (math $i + 1)
                if test $next_i -gt (count $argv)
                    echo "$RED"Error:"$RESET Option '$argv[$i]' requires an argument." >&2
                    exit 1
                end
                set custom_rule $argv[$next_i]
                set i (math $i + 2)
            case -p --print
                set print_only true
                set i (math $i + 1)
            case -d --diff-only
                set diff_only true
                set i (math $i + 1)
            case --restore-rule
                do_restore_rule
                exit $status
            case --rule-path
                set show_rule_path true
                set i (math $i + 1)
            case -v --version
                echo "gdiff v$VERSION"
                exit 0
            case -h --help
                show_help
                exit 0
            case '*'
                echo "$RED"Unknown option:"$RESET '$argv[$i]'" >&2
                echo "  Run 'gdiff --help' for a list of valid options." >&2
                exit 1
        end
    end

    set -l rule_file ""
    if test "$diff_only" = false
        set rule_file (resolve_rule "$custom_rule")
        if test $status -ne 0
            exit 1
        end
    end

    if test "$show_rule_path" = true
        echo "$rule_file"
        exit 0
    end

    if test "$diff_only" = false
        lazy_init
    end

    if test "$diff_only" = false; and not test -s "$rule_file"
        echo "$RED"Error:"$RESET Rule file is empty: $rule_file" >&2
        echo "Please edit the file or run 'gdiff --restore-rule' to restore the default rule." >&2
        exit 1
    end

    if not type -q git
        echo "$RED"Error:"$RESET git is not installed." >&2
        exit 1
    end

    if not git rev-parse --git-dir >/dev/null 2>&1
        echo "$RED"Error:"$RESET Not inside a git repository." >&2
        exit 1
    end

    if git diff --cached --quiet
        echo "$RED"Nothing staged."$RESET Use 'git add' to stage your changes first." >&2
        exit 1
    end

    if test "$print_only" = true
        stream_content "$rule_file"
        return 0
    end

    set -l clipboard_cmd (detect_clipboard)

    if test -z "$clipboard_cmd"
        echo "$RED"Error:"$RESET No clipboard tool found (wl-copy, xclip, xsel, pbcopy, clip.exe)." >&2
        echo "Use --print to output to stdout instead." >&2
        exit 1
    end

    if stream_content "$rule_file" | eval "$clipboard_cmd"
        if test "$diff_only" = true
            echo "$GREEN"✓"$RESET Diff copied to clipboard"
        else
            echo "$GREEN"✓"$RESET Diff + rule copied to clipboard"
        end
    else
        echo "$RED"Error:"$RESET Failed to copy to clipboard." >&2
        exit 1
    end
end

main $argv
