# =============================================================================
# ~/.zshrc
# =============================================================================
# Reihenfolge ist hier Absicht:
#   1. Profiling-Schalter
#   2. tmux-exec  (ganz oben, damit die aeussere Shell sich die Init spart)
#   3. billige Optionen / Keybindings / History
#   4. teure Sachen: compinit + gecachte eval-Ausgaben
#   5. Aliases, Funktionen, PATH
#
# Cache leeren nach Theme-/Tool-Update:   zshrc-refresh
# Startzeit messen:                       ZSHRC_PROFILE=1 zsh -i -c exit
# =============================================================================


# -----------------------------------------------------------------------------
# 1. Profiling (optional, per Env-Variable)
# -----------------------------------------------------------------------------
if [[ -n "$ZSHRC_PROFILE" ]]; then
    zmodload zsh/zprof
fi


# -----------------------------------------------------------------------------
# 2. tmux-Autostart
# -----------------------------------------------------------------------------
# Muss vor allem anderen stehen: die aeussere Shell wird durch tmux ersetzt und
# muss deshalb gar nicht erst komplett initialisiert werden. Frueher lief das
# zshrc pro Terminalstart zweimal komplett durch (einmal aussen, einmal im
# tmux-Fenster) - das faellt damit weg.
#
# Terminalerkennung laeuft ueber Environment-Variablen statt ueber ps/proc,
# das spart ~6 Forks pro Shellstart.
if [[ -o interactive && -z "$TMUX" && -z "$ZSHRC_PROFILE" && $UID -ne 0 && -t 1 ]]; then
    # IDEs und eingebettete Terminals explizit ausnehmen
    if [[ -z "$TERMINAL_EMULATOR" && -z "$INSIDE_EMACS" \
       && -z "$VSCODE_INJECTION" && -z "$NVIM" ]]; then

        _zsh_want_tmux=0
        [[ "$TERM_PROGRAM" == ghostty || -n "$GHOSTTY_RESOURCES_DIR" ]] && _zsh_want_tmux=1
        [[ -n "$KITTY_WINDOW_ID" ]]                                    && _zsh_want_tmux=1
        [[ -n "$VTE_VERSION" ]]                                        && _zsh_want_tmux=1  # xfce4-terminal, gnome-terminal
        [[ -n "$ZSH_FORCE_TMUX" ]]                                     && _zsh_want_tmux=1  # manueller Override
        [[ -n "$ZSH_NO_TMUX" ]]                                        && _zsh_want_tmux=0

        if (( _zsh_want_tmux )) && (( $+commands[tmux] )); then
            unset _zsh_want_tmux
            exec tmux new-session -A -s main
        fi
        unset _zsh_want_tmux
    fi
fi


# -----------------------------------------------------------------------------
# 3. Grundoptionen, Keybindings, History
# -----------------------------------------------------------------------------
bindkey -e                       # Emacs-Keybindings, auch wenn EDITOR=vi
setopt interactivecomments       # "#" auf der Kommandozeile = Kommentar

HISTFILE=~/.zsh_history
HISTSIZE=50000                   # Eintraege im RAM
SAVEHIST=50000                   # Eintraege in der Datei
                                 # (vorher stand SAVEHIST auf 1000 - HISTFILESIZE
                                 #  ist eine Bash-Variable und hat nichts getan)

setopt hist_ignore_all_dups      # aeltere Duplikate rauswerfen
setopt hist_ignore_space         # Zeilen mit fuehrendem Leerzeichen nicht merken
setopt hist_reduce_blanks
setopt hist_verify               # Expansion erst anzeigen, dann ausfuehren
setopt extended_history          # mit Zeitstempel (Ersatz fuer HISTTIMEFORMAT)
setopt share_history             # History zwischen laufenden Shells teilen

# Falls die Shell sich beim Start traege anfuehlt, obwohl sonst alles schnell
# ist: share_history liest bei jedem Prompt die History-Datei neu ein. Dann
# stattdessen mal testen:
#   unsetopt share_history
#   setopt inc_append_history


# -----------------------------------------------------------------------------
# 4a. Cache-Verzeichnis
# -----------------------------------------------------------------------------
ZSH_CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/zsh
[[ -d $ZSH_CACHE_DIR ]] || mkdir -p $ZSH_CACHE_DIR

# Pfad zum oh-my-posh-Theme
OMP_CONFIG=$HOME/.zsh/rudolfs-dark.omp.json


# -----------------------------------------------------------------------------
# 4b. Completion-System
# -----------------------------------------------------------------------------
# Nacktes "compinit" laeuft bei jedem Start compaudit und statet alle
# $fpath-Verzeichnisse ab - hunderte stat()-Calls. Bei warmem Page-Cache egal,
# bei kaltem Cache (also genau nach Idle) der teuerste Einzelposten.
# Deshalb: voller Audit nur einmal pro Tag, sonst direkt aus dem Dump.
() {
    emulate -L zsh
    setopt local_options extended_glob

    local zdump=$ZSH_CACHE_DIR/zcompdump

    autoload -Uz compinit
    if [[ -n $zdump(#qNmh-24) ]]; then
        compinit -C -d $zdump          # Dump juenger als 24h -> Check ueberspringen
    else
        compinit -d $zdump             # einmal taeglich voll durchlaufen
        touch $zdump
    fi

    # Dump kompilieren: laedt deutlich schneller, gerade von kalter Platte
    if [[ ! -s ${zdump}.zwc || $zdump -nt ${zdump}.zwc ]]; then
        zcompile $zdump 2>/dev/null
    fi
}

zstyle ':completion:*' auto-description 'specify: %d'
zstyle ':completion:*' completer _expand _complete _correct _approximate
zstyle ':completion:*' format 'Completing %d'
zstyle ':completion:*' group-name ''
zstyle ':completion:*' menu select=long
zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s
zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*'
zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s
zstyle ':completion:*' use-compctl false
zstyle ':completion:*' verbose true

# Completion-Ergebnisse cachen (z.B. apt-Paketlisten)
zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path $ZSH_CACHE_DIR/compcache

# list-colors: die Zeile "zstyle ':completion:*' list-colors ''" im alten zshrc
# hat die LS_COLORS-Zuweisung direkt darueber wieder plattgemacht - deshalb hier
# nur noch einmal, weiter unten nach dircolors.

zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'

# SSH-Hosts: mit "zstyle -e" wird das erst beim Tab-Druck ausgewertet,
# nicht mehr bei jedem Shellstart.
zstyle -e ':completion:*:*:ssh:*' hosts \
    'reply=(${(f)"$(grep -h "^Host " ~/.ssh/config ~/.ssh/config.d/*(N) 2>/dev/null | sed "s/^Host //" | tr " " "\n" | grep -v "[*?]")"})'


# -----------------------------------------------------------------------------
# 4c. Gecachte Init-Ausgaben (television, dircolors)
# -----------------------------------------------------------------------------
# Beide Tools geben bei jedem Start denselben statischen Shell-Code aus. Statt
# sie jedes Mal zu starten, wird die Ausgabe einmal in eine Datei geschrieben,
# kompiliert und danach nur noch gesourct.
#
# WICHTIG: die Bloecke brauchen eine Trennzeile. Manche Tools beenden ihre
# Ausgabe ohne Newline, dann klebt die erste Zeile des naechsten Blocks hinten
# an der letzten Zeile des vorigen - und man bekommt kaputte Pfade wie
# ".../init.26.0.5.abc..zsh#compdef".
() {
    emulate -L zsh
    local cache=$ZSH_CACHE_DIR/init.zsh
    local stale=0

    [[ -s $cache ]] || stale=1
    [[ -f ~/.dircolors  && ~/.dircolors  -nt $cache ]] && stale=1
    [[ -n $commands[tv] && $commands[tv] -nt $cache ]] && stale=1

    if (( stale )); then
        {
            if (( $+commands[tv] )); then
                tv init zsh
                print
            fi
            if (( $+commands[dircolors] )); then
                if [[ -r ~/.dircolors ]]; then
                    dircolors -b ~/.dircolors
                else
                    dircolors -b
                fi
                print
            fi
        } > $cache.tmp.$$ 2>/dev/null && mv -f $cache.tmp.$$ $cache
        rm -f $cache.tmp.$$
        zcompile $cache 2>/dev/null
    fi

    [[ -s $cache ]] && source $cache
}

# oh-my-posh cacht seinen Init-Code seit v26 selbst unter ~/.cache/oh-my-posh/
# (Dateiname enthaelt Version + Config-Hash). "oh-my-posh init zsh" gibt nur
# noch einen kleinen Stub aus, der diese Datei sourct. Ein eigener Cache
# darueber bringt deshalb nichts und bricht, sobald sich Version oder Theme
# aendert - der Stub zeigt dann auf einen Pfad, den es nicht mehr gibt.
if (( $+commands[oh-my-posh] )); then
    eval "$(oh-my-posh init zsh --config "$OMP_CONFIG")"
fi

# Jetzt steht LS_COLORS -> Completion einfaerben
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}

# Cache verwerfen und Shell neu starten
zshrc-refresh() {
    rm -f $ZSH_CACHE_DIR/init.zsh{,.zwc} \
          $ZSH_CACHE_DIR/zcompdump{,.zwc} \
          ~/.zshrc.zwc
    # oh-my-posh raeumt seinen eigenen Cache normalerweise selbst auf.
    # Falls das Prompt nach einem Update zickt, zusaetzlich:
    #   rm -rf ~/.cache/oh-my-posh
    echo "Cache geleert, starte Shell neu ..."
    exec zsh
}


# -----------------------------------------------------------------------------
# 5. PATH
# -----------------------------------------------------------------------------
typeset -U path PATH             # automatisch dedupliziert
path=(
    $HOME/.local/bin             # pip3 --user
    $path
    $HOME/go/bin
    $HOME/.cargo/bin
)
path=($^path(N-/))               # nur existierende Verzeichnisse behalten


# -----------------------------------------------------------------------------
# 6. Aliases
# -----------------------------------------------------------------------------
alias ls='ls --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'

[[ -f ~/.bash_aliases ]]          && source ~/.bash_aliases
[[ -f ~/.config/common_aliases ]] && source ~/.config/common_aliases


# -----------------------------------------------------------------------------
# 7. tmux-Fenstername = aktuelles Verzeichnis
# -----------------------------------------------------------------------------
# Vorher via PROMPT_COMMAND - das ist eine Bash-Variable und hat in zsh nie
# funktioniert. Jetzt korrekt als chpwd-Hook: laeuft nur beim Verzeichnis-
# wechsel, nicht bei jedem Prompt.
if [[ -n "$TMUX" ]]; then
    autoload -Uz add-zsh-hook
    _tmux_rename_window() { tmux rename-window "${PWD:t}" 2>/dev/null }
    add-zsh-hook chpwd _tmux_rename_window
    _tmux_rename_window
fi


# -----------------------------------------------------------------------------
# 8. Funktionen
# -----------------------------------------------------------------------------

# yazi mit cwd-Uebernahme
function y() {
    local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
    yazi "$@" --cwd-file="$tmp"
    IFS= read -r -d '' cwd < "$tmp"
    [ -n "$cwd" ] && [ "$cwd" != "$PWD" ] && builtin cd -- "$cwd"
    rm -f -- "$tmp"
}

# --- Bandcamp -----------------------------------------------------------------

function bandcampdl() {
    yt-dlp \
        -x \
        --audio-format mp3 \
        --audio-quality 0 \
        --embed-metadata \
        --embed-thumbnail \
        --convert-thumbnails jpg \
        -o "%(album_artist)s/%(release_year)s - %(album)s/%(album_artist)s - %(album)s - %(track_number)02d - %(title)s.%(ext)s" \
        "$1"
}

function bandcampbatch() {
    local file="$1"

    while IFS= read -r url; do
        [[ -z "$url" || "$url" == \#* ]] && continue
        bandcampdl "$url"
    done < "$file"
}

function bandcamplist() {
    local url outfile tmpfile band count

    command -v yt-dlp >/dev/null 2>&1 || {
        echo "Fehler: yt-dlp wurde nicht gefunden."
        return 1
    }

    if (( $# < 1 || $# > 2 )); then
        echo "Usage:"
        echo "    bandcamplist <https://band.bandcamp.com/music> [output.txt]"
        return 1
    fi

    url="$1"

    if [[ ! "$url" =~ ^https?://([^.]+)\.bandcamp\.com/music/?$ ]]; then
        echo "Fehler: Keine gueltige Bandcamp-/music-URL:"
        echo "    $url"
        return 1
    fi

    band="${match[1]}"

    if [[ $# -eq 2 ]]; then
        outfile="$2"
    else
        outfile="bandcamp-${band}.txt"
    fi

    tmpfile=$(mktemp)

    if ! yt-dlp \
        --flat-playlist \
        --print webpage_url \
        "$url" \
        | sort -u > "$tmpfile"
    then
        rm -f "$tmpfile"
        echo "Fehler beim Abrufen der Links."
        return 1
    fi

    count=$(wc -l < "$tmpfile")

    if (( count == 0 )); then
        rm -f "$tmpfile"
        echo "Keine Album- oder Track-Links gefunden."
        return 1
    fi

    mv "$tmpfile" "$outfile"

    echo "✓ $count Links nach '$outfile' geschrieben."
}

# tm [name]  -> Session anlegen oder hinwechseln (Default: main)
function tm() {
    local s=${1:-main}
    if [[ -n "$TMUX" ]]; then
        tmux has-session -t "=$s" 2>/dev/null || tmux new-session -d -s "$s"
        tmux switch-client -t "=$s"
    else
        tmux new-session -A -s "$s"
    fi
}

# -----------------------------------------------------------------------------
# 9. Abschluss
# -----------------------------------------------------------------------------

# zshrc selbst kompilieren - zsh benutzt die .zwc-Datei automatisch, solange sie
# neuer ist als das Original. Nach jeder Aenderung wird sie hier neu gebaut.
if [[ ! -s ~/.zshrc.zwc || ~/.zshrc -nt ~/.zshrc.zwc ]]; then
    zcompile ~/.zshrc 2>/dev/null
fi

if [[ -n "$ZSHRC_PROFILE" ]]; then
    zprof
fi
