#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"

PROJECT_ROOTS=(
    "$HOME/Projekte"
    "$HOME/Projects"
    "$HOME/Code"
    "$HOME/Developer"
    "$HOME/dev"
    "$HOME/test"
)

notify() {
    notify-send "󰅩 Dev Menue" "$1" >/dev/null 2>&1 || true
}

pick() {
    wofi --dmenu --prompt "$1" --insensitive
}

terminal_hold() {
    local title="$1"
    shift

    if command -v kitty >/dev/null 2>&1; then
        kitty --title "$title" sh -lc "$*; printf '\n'; read -r -p 'Enter zum Schliessen... ' _"
    else
        notify "kitty ist nicht installiert."
    fi
}

shell_quote() {
    printf '%q' "$1"
}

code_cmd() {
    if command -v code >/dev/null 2>&1; then
        printf '%s\n' code
    elif command -v codium >/dev/null 2>&1; then
        printf '%s\n' codium
    else
        return 1
    fi
}

docker_available() {
    if ! command -v docker >/dev/null 2>&1; then
        notify "Docker ist nicht installiert."
        return 1
    fi

    if ! docker info >/dev/null 2>&1; then
        notify "Docker laeuft nicht oder ist nicht erreichbar."
        return 1
    fi
}

has_compose() {
    local project="$1"

    [[ -f "$project/compose.yml" ||
        -f "$project/compose.yaml" ||
        -f "$project/docker-compose.yml" ||
        -f "$project/docker-compose.yaml" ]]
}

project_label() {
    local project="$1"
    local marker=""

    if [[ -d "$project/.git" ]]; then
        marker+=" "
    fi

    if has_compose "$project"; then
        marker+="󰡨 "
    fi

    printf '%s%s' "$marker" "${project#$HOME/}"
}

pick_project() {
    local roots=()
    local projects=()
    local labels=()
    local root project choice

    for root in "${PROJECT_ROOTS[@]}"; do
        [[ -d "$root" ]] && roots+=("$root")
    done

    if ((${#roots[@]} == 0)); then
        notify "Keine Projektordner gefunden."
        return 1
    fi

    mapfile -t projects < <(
        {
            find "${roots[@]}" -maxdepth 4 -type d -name .git -printf '%h\n' 2>/dev/null
            find "${roots[@]}" -maxdepth 3 -type d \( -name node_modules -o -name vendor \) -prune -o \
                -type f \( -name compose.yml -o -name compose.yaml -o -name docker-compose.yml -o -name docker-compose.yaml -o -name package.json -o -name Cargo.toml -o -name pyproject.toml -o -name go.mod \) \
                -printf '%h\n' 2>/dev/null
        } |
            sort -u
    )

    if ((${#projects[@]} == 0)); then
        notify "Keine Projekte gefunden."
        return 1
    fi

    for project in "${projects[@]}"; do
        labels+=("$(project_label "$project")")
    done

    choice="$(printf '%s\n' "${labels[@]}" | pick "📁  Projekt")"
    [[ -z "${choice:-}" ]] && return 1

    for i in "${!labels[@]}"; do
        if [[ "$choice" == "${labels[$i]}" ]]; then
            printf '%s\n' "${projects[$i]}"
            return 0
        fi
    done

    return 1
}

open_project_browser() {
    local project="$1"
    local choice url

    choice="$(
        printf '%s\n' \
            "🌐  http://localhost:3000" \
            "🌐  http://localhost:5173" \
            "🌐  http://localhost:8000" \
            "🌐  http://localhost:8080" \
            "🌐  http://localhost:5000" \
            "🌐  http://localhost:4200" \
            "📂  Projektordner im Browser" |
            pick "🌐  Projekt im Browser"
    )"

    case "$choice" in
        *"Projektordner"*)
            xdg-open "$project" >/dev/null 2>&1 &
            ;;
        *"http"*)
            url="${choice#*  }"
            xdg-open "$url" >/dev/null 2>&1 &
            ;;
    esac
}

project_menu() {
    local project project_q choice editor

    project="$(pick_project)" || return 0
    project_q="$(shell_quote "$project")"

    choice="$(
        printf '%s\n' \
            "📂  Projekt oeffnen (Code)" \
            "🌐  Projekt im Browser oeffnen" \
            "🐳  Docker Compose starten" \
            "🛑  Docker stoppen" \
            "🔄  Container neu starten" \
            "📜  Logs anzeigen" \
            "📦  Git Repo Status anzeigen" |
            pick "📁  $(basename "$project")"
    )"

    case "$choice" in
        *"Projekt oeffnen"*)
            if editor="$(code_cmd)"; then
                "$editor" "$project" >/dev/null 2>&1 &
            else
                notify "VS Code/Codium ist nicht installiert."
            fi
            ;;
        *"Browser"*)
            open_project_browser "$project"
            ;;
        *"Docker Compose starten"*)
            docker_available || return 0
            if has_compose "$project"; then
                terminal_hold "Docker Compose: $(basename "$project")" "cd $project_q && docker compose up -d && docker compose ps"
            else
                notify "Kein Docker-Compose File im Projekt."
            fi
            ;;
        *"Docker stoppen"*)
            docker_available || return 0
            if has_compose "$project"; then
                terminal_hold "Docker Stop: $(basename "$project")" "cd $project_q && docker compose stop && docker compose ps"
            else
                notify "Kein Docker-Compose File im Projekt."
            fi
            ;;
        *"Container neu starten"*)
            docker_available || return 0
            if has_compose "$project"; then
                terminal_hold "Docker Restart: $(basename "$project")" "cd $project_q && docker compose restart && docker compose ps"
            else
                notify "Kein Docker-Compose File im Projekt."
            fi
            ;;
        *"Logs anzeigen"*)
            docker_available || return 0
            if has_compose "$project"; then
                if command -v kitty >/dev/null 2>&1; then
                    kitty --title "Logs: $(basename "$project")" sh -lc "cd $project_q && docker compose logs -f --tail=200"
                else
                    notify "kitty ist nicht installiert."
                fi
            else
                notify "Kein Docker-Compose File im Projekt."
            fi
            ;;
        *"Git Repo Status"*)
            if [[ -d "$project/.git" ]]; then
                terminal_hold "Git Status: $(basename "$project")" "cd $project_q && git status --short --branch"
            else
                notify "Kein Git Repository."
            fi
            ;;
    esac
}

pick_container() {
    local containers=()
    local labels=()
    local line name status choice

    docker_available || return 1

    mapfile -t containers < <(docker ps -a --format '{{.Names}}|{{.Status}}' | sort)
    if ((${#containers[@]} == 0)); then
        notify "Keine Docker Container gefunden."
        return 1
    fi

    for line in "${containers[@]}"; do
        name="${line%%|*}"
        status="${line#*|}"
        labels+=("🐳  $name  ·  $status")
    done

    choice="$(printf '%s\n' "${labels[@]}" | pick "🐳  Container")"
    [[ -z "${choice:-}" ]] && return 1

    for i in "${!labels[@]}"; do
        if [[ "$choice" == "${labels[$i]}" ]]; then
            printf '%s\n' "${containers[$i]%%|*}"
            return 0
        fi
    done

    return 1
}

docker_menu() {
    local choice container running_ids all_ids

    choice="$(
        printf '%s\n' \
            "▶️  Alle Container starten" \
            "⏹️  Alle stoppen" \
            "🔄  Einzelnen Container neu starten" \
            "📊  docker stats" \
            "📜  Logs anzeigen" \
            "🧹  Cleanup dangling images" |
            pick "🐳  Docker Control"
    )"

    case "$choice" in
        *"Alle Container starten"*)
            docker_available || return 0
            all_ids="$(docker ps -aq)"
            if [[ -n "$all_ids" ]]; then
                terminal_hold "Docker Start" "docker start $all_ids && docker ps"
            else
                notify "Keine Container gefunden."
            fi
            ;;
        *"Alle stoppen"*)
            docker_available || return 0
            running_ids="$(docker ps -q)"
            if [[ -n "$running_ids" ]]; then
                terminal_hold "Docker Stop" "docker stop $running_ids && docker ps -a"
            else
                notify "Keine laufenden Container."
            fi
            ;;
        *"Einzelnen Container neu starten"*)
            container="$(pick_container)" || return 0
            terminal_hold "Docker Restart: $container" "docker restart '$container' && docker ps -a --filter name='^/$container$'"
            ;;
        *"docker stats"*)
            docker_available || return 0
            if command -v kitty >/dev/null 2>&1; then
                kitty --title "docker stats" sh -lc "docker stats"
            else
                notify "kitty ist nicht installiert."
            fi
            ;;
        *"Logs anzeigen"*)
            container="$(pick_container)" || return 0
            if command -v kitty >/dev/null 2>&1; then
                kitty --title "Logs: $container" sh -lc "docker logs -f --tail=200 '$container'"
            else
                notify "kitty ist nicht installiert."
            fi
            ;;
        *"Cleanup dangling images"*)
            docker_available || return 0
            terminal_hold "Docker Cleanup" "docker image prune -f"
            ;;
    esac
}

launch_codex() {
    if ! command -v kitty >/dev/null 2>&1; then
        notify "kitty ist nicht installiert."
        return 0
    fi

    if ! command -v codex >/dev/null 2>&1; then
        notify "codex ist nicht installiert."
        return 0
    fi

    kitty --title "Codex" sh -lc 'cd "$HOME" && exec codex' >/dev/null 2>&1 &
}

launch_opencode() {
    if ! command -v kitty >/dev/null 2>&1; then
        notify "kitty ist nicht installiert."
        return 0
    fi

    if ! command -v opencode >/dev/null 2>&1; then
        notify "opencode ist nicht installiert."
        return 0
    fi

    kitty --title "opencode" sh -lc 'cd "$HOME" && exec opencode' >/dev/null 2>&1 &
}

choice="$(
    printf '%s\n' \
        "📁  Projekt Management" \
        "󰌘  Homelab Controlcenter" \
        "🐳  Docker Control" \
        "󰚩  Codex" \
        "󰚩  opencode" \
        "  Terminal" \
        "  Projektordner" \
        "  VS Code / Codium" \
        "󰊢  Git GUI" |
        pick "󰅩  Dev Menue"
)"

case "$choice" in
    *"Projekt Management"*)
        project_menu
        ;;
    *"Homelab Controlcenter"*)
        "$SCRIPT_DIR/homelab-control.sh"
        ;;
    *"Docker Control"*)
        docker_menu
        ;;
    *"Codex"*)
        launch_codex
        ;;
    *"opencode"*)
        launch_opencode
        ;;
    *"Terminal"*)
        kitty
        ;;
    *"Projektordner"*)
        nautilus
        ;;
    *"VS Code"*|*"Codium"*)
        if editor="$(code_cmd)"; then
            "$editor" >/dev/null 2>&1 &
        else
            notify "VS Code/Codium ist nicht installiert."
        fi
        ;;
    *"Git GUI"*)
        if command -v gitg >/dev/null 2>&1; then
            gitg
        elif command -v git-cola >/dev/null 2>&1; then
            git-cola
        else
            notify "gitg oder git-cola ist nicht installiert."
        fi
        ;;
esac
