#!/bin/bash
set -euo pipefail

KUGETSU_DIR="${KUGETSU_DIR:-$HOME/.kugetsu}"
SESSIONS_DIR="$KUGETSU_DIR/sessions"
BIN_DIR="$KUGETSU_DIR/bin"

usage() {
    cat << 'EOF'
kugetsu - OpenCode Session Manager

Usage:
    kugetsu start <session_id> <message> [--debug]    Start a new session
    kugetsu list [--all]                               List sessions (default: left only)
    kugetsu resume <session_id> [message] [--debug]   Resume a session
    kugetsu stop <session_id> [--debug]               Stop a session gracefully
    kugetsu destroy <session_id> [-y] [--debug]      Delete a session (prompts confirmation)
    kugetsu destroy --all [-y]                        Delete all sessions (prompts confirmation)
    kugetsu help                                      Show this help

States:
    used    - Session is active (process running)
    idle    - Session ended gracefully (not resumable)
    left    - Session interrupted/crashed (resumable)
    invalid - Session data missing/corrupt

Options:
    --debug   Show real-time debug output and capture to debug.log

Examples:
    kugetsu start mytask "fix bug #1"
    kugetsu start mytask "fix bug #1" --debug
    kugetsu list
    kugetsu list --all
    kugetsu resume mytask
    kugetsu resume mytask "continue working" --debug
    kugetsu stop mytask --debug
    kugetsu destroy mytask --debug
    kugetsu destroy mytask -y
    kugetsu destroy --all
    kugetsu destroy --all -y
EOF
}

ensure_dirs() {
    mkdir -p "$SESSIONS_DIR" "$BIN_DIR"
}

validate_session_id() {
    local session_id="$1"
    if [ -z "$session_id" ]; then
        echo "Error: session_id cannot be empty" >&2
        exit 1
    fi
}

get_session_dir() {
    local session_id="$1"
    echo "$SESSIONS_DIR/$session_id"
}

get_state() {
    local session_dir="$1"
    if [ -f "$session_dir/state" ]; then
        cat "$session_dir/state"
    else
        echo "invalid"
    fi
}

DEBUG_MODE=false

set_debug_mode() {
    DEBUG_MODE=false
    local filtered_args=()
    while [ $# -gt 0 ]; do
        case "$1" in
            --debug)
                DEBUG_MODE=true
                ;;
            *)
                filtered_args+=("$1")
                ;;
        esac
        shift
    done
    echo "${filtered_args[@]}"
}

show_debug_log() {
    local session_dir="$1"
    local debug_log="$session_dir/debug.log"
    if [ -f "$debug_log" ]; then
        echo "=== Debug Log ==="
        cat "$debug_log"
        echo "=== End Debug Log ==="
    else
        echo "No debug log found"
    fi
}

set_state() {
    local session_dir="$1"
    local state="$2"
    echo "$state" > "$session_dir/state"
}

is_process_running() {
    local pid="$1"
    if kill -0 "$pid" 2>/dev/null; then
        return 0
    else
        return 1
    fi
}

check_and_update_state() {
    local session_dir="$1"
    local state=$(get_state "$session_dir")
    
    if [ "$state" = "used" ]; then
        local pid_file="$session_dir/pid"
        if [ -f "$pid_file" ]; then
            local pid=$(cat "$pid_file")
            if ! is_process_running "$pid"; then
                set_state "$session_dir" "left"
                return 1
            fi
        else
            set_state "$session_dir" "left"
            return 1
        fi
    fi
    return 0
}

cmd_start() {
    local session_id=""
    local message=""
    
    while [ $# -gt 0 ]; do
        case "$1" in
            --debug)
                DEBUG_MODE=true
                ;;
            *)
                if [ -z "$session_id" ]; then
                    session_id="$1"
                elif [ -z "$message" ]; then
                    message="$1"
                fi
                ;;
        esac
        shift
    done
    
    if [ -z "$session_id" ] || [ -z "$message" ]; then
        echo "Error: start requires <session_id> and <message>" >&2
        exit 1
    fi
    
    validate_session_id "$session_id"
    local session_dir=$(get_session_dir "$session_id")
    
    ensure_dirs
    
    if [ -d "$session_dir" ]; then
        local state=$(get_state "$session_dir")
        check_and_update_state "$session_dir"
        state=$(get_state "$session_dir")
        
        if [ "$state" = "used" ]; then
            echo "Error: session '$session_id' is already in use (state=used)" >&2
            echo "Use 'kugetsu list' to see all sessions, or 'kugetsu resume $session_id' to resume" >&2
            exit 1
        fi
        
        if [ "$state" = "left" ]; then
            echo "Warning: session '$session_id' was left interrupted" >&2
            echo "Resuming instead of starting new..." >&2
            cmd_resume "$session_id" "$message"
            return
        fi
    fi
    
    mkdir -p "$session_dir"
    set_state "$session_dir" "used"
    echo "$$" > "$session_dir/pid"
    echo "$message" > "$session_dir/message"
    
    echo "Starting session '$session_id'..."
    if [ "$DEBUG_MODE" = true ]; then
        opencode run --print-logs --log-level DEBUG --session "$session_id" "$message" 2>&1 | tee "$session_dir/debug.log"
    else
        opencode run --session "$session_id" "$message"
    fi
    local exit_code=$?
    
    if [ $exit_code -eq 0 ]; then
        set_state "$session_dir" "idle"
    else
        set_state "$session_dir" "left"
    fi
    
    rm -f "$session_dir/pid"
}

cmd_list() {
    local show_all=false
    if [ $# -ge 1 ] && [ "$1" = "--all" ]; then
        show_all=true
    fi
    
    ensure_dirs
    
    printf "%-20s %-10s %-s\n" "SESSION_ID" "STATE" "LAST_MESSAGE"
    printf "%-20s %-10s %-s\n" "──────────" "─────" "───────────"
    
    for session_dir in "$SESSIONS_DIR"/*; do
        if [ -d "$session_dir" ]; then
            local session_id=$(basename "$session_dir")
            check_and_update_state "$session_dir"
            local state=$(get_state "$session_dir")
            
            if [ "$show_all" = false ] && [ "$state" != "left" ]; then
                continue
            fi
            
            local message=""
            if [ -f "$session_dir/message" ]; then
                message=$(cat "$session_dir/message")
                if [ ${#message} -gt 40 ]; then
                    message="${message:0:37}..."
                fi
            fi
            
            printf "%-20s %-10s %-s\n" "$session_id" "$state" "$message"
        fi
    done
}

cmd_resume() {
    local session_id=""
    local message=""
    local args=("$@")
    
    for arg in "${args[@]}"; do
        case "$arg" in
            --debug)
                DEBUG_MODE=true
                ;;
            *)
                if [ -z "$session_id" ]; then
                    session_id="$arg"
                elif [ -z "$message" ]; then
                    message="$arg"
                fi
                ;;
        esac
    done
    
    if [ -z "$session_id" ]; then
        echo "Error: resume requires <session_id>" >&2
        exit 1
    fi
    
    validate_session_id "$session_id"
    
    local session_dir=$(get_session_dir "$session_id")
    
    if [ ! -d "$session_dir" ]; then
        echo "Error: session '$session_id' not found" >&2
        exit 1
    fi
    
    check_and_update_state "$session_dir"
    local state=$(get_state "$session_dir")
    
    if [ "$state" = "used" ]; then
        echo "Warning: session '$session_id' is marked as used" >&2
        local pid=""
        if [ -f "$session_dir/pid" ]; then
            pid=$(cat "$session_dir/pid")
        fi
        if [ -n "$pid" ] && is_process_running "$pid"; then
            echo "Error: process $pid is still running for this session" >&2
            exit 1
        else
            set_state "$session_dir" "left"
            state="left"
        fi
    fi
    
    if [ "$state" = "idle" ]; then
        echo "Error: session '$session_id' ended gracefully (state=idle)" >&2
        echo "This session cannot be resumed. Start a new session instead." >&2
        exit 1
    fi
    
    if [ "$state" = "invalid" ]; then
        echo "Error: session '$session_id' is invalid (state=invalid)" >&2
        exit 1
    fi
    
    if [ -z "$message" ]; then
        if [ -f "$session_dir/message" ]; then
            message=$(cat "$session_dir/message")
            echo "Auto-filled message: $message"
        else
            echo "Error: no message stored for session '$session_id'" >&2
            echo "Provide a message as second argument: kugetsu resume $session_id <message>" >&2
            exit 1
        fi
    else
        echo "Using provided message: $message"
    fi
    
    set_state "$session_dir" "used"
    echo "$$" > "$session_dir/pid"
    echo "$message" > "$session_dir/message"
    
    echo "Resuming session '$session_id'..."
    if [ "$DEBUG_MODE" = true ]; then
        opencode run --print-logs --log-level DEBUG --continue --session "$session_id" "$message" 2>&1 | tee "$session_dir/debug.log"
    else
        opencode run --continue --session "$session_id" "$message"
    fi
    local exit_code=$?
    
    if [ $exit_code -eq 0 ]; then
        set_state "$session_dir" "idle"
    else
        set_state "$session_dir" "left"
    fi
    
    rm -f "$session_dir/pid"
}

cmd_stop() {
    local session_id=""
    
    while [ $# -gt 0 ]; do
        case "$1" in
            --debug)
                DEBUG_MODE=true
                ;;
            *)
                if [ -z "$session_id" ]; then
                    session_id="$1"
                fi
                ;;
        esac
        shift
    done
    
    if [ -z "$session_id" ]; then
        echo "Error: stop requires <session_id>" >&2
        exit 1
    fi
    
    validate_session_id "$session_id"
    local session_dir=$(get_session_dir "$session_id")
    
    if [ ! -d "$session_dir" ]; then
        echo "Error: session '$session_id' not found" >&2
        exit 1
    fi
    
    if [ "$DEBUG_MODE" = true ]; then
        show_debug_log "$session_dir"
    fi
    
    local state=$(get_state "$session_dir")
    
    if [ "$state" != "used" ]; then
        echo "Error: session '$session_id' is not in use (state=$state)" >&2
        exit 1
    fi
    
    local pid=""
    if [ -f "$session_dir/pid" ]; then
        pid=$(cat "$session_dir/pid")
    fi
    
    if [ -n "$pid" ] && is_process_running "$pid"; then
        echo "Sending SIGTERM to process $pid..."
        kill -TERM "$pid" 2>/dev/null || true
        
        local count=0
        while is_process_running "$pid" && [ $count -lt 10 ]; do
            sleep 0.5
            count=$((count + 1))
        done
        
        if is_process_running "$pid"; then
            echo "Process still running, sending SIGKILL..." >&2
            kill -KILL "$pid" 2>/dev/null || true
        fi
    fi
    
    set_state "$session_dir" "idle"
    rm -f "$session_dir/pid"
    
    echo "Session '$session_id' stopped"
}

cmd_destroy() {
    local session_id=""
    local destroy_all=false
    local force=false
    
    while [ $# -gt 0 ]; do
        case "$1" in
            --all)
                destroy_all=true
                ;;
            --debug)
                DEBUG_MODE=true
                ;;
            -y|--yes)
                force=true
                ;;
            -*)
                echo "Error: unknown option '$1'" >&2
                exit 1
                ;;
            *)
                if [ -n "$session_id" ]; then
                    echo "Error: too many arguments" >&2
                    exit 1
                fi
                session_id="$1"
                ;;
        esac
        shift
    done
    
    if [ "$destroy_all" = true ]; then
        if [ -n "$session_id" ]; then
            echo "Error: cannot specify session_id with --all" >&2
            exit 1
        fi
        
        if [ "$force" = true ]; then
            rm -rf "$SESSIONS_DIR"/*
            echo "All sessions deleted"
            return
        fi
        
        echo "Delete ALL sessions? [y/N] "
        local reply
        read reply
        if [ "$reply" = "y" ] || [ "$reply" = "Y" ]; then
            rm -rf "$SESSIONS_DIR"/*
            echo "All sessions deleted"
        else
            echo "Aborted"
        fi
        return
    fi
    
    if [ -z "$session_id" ]; then
        echo "Error: destroy requires <session_id> or --all" >&2
        exit 1
    fi
    
    validate_session_id "$session_id"
    local session_dir=$(get_session_dir "$session_id")
    
    if [ ! -d "$session_dir" ]; then
        echo "Error: session '$session_id' not found" >&2
        exit 1
    fi
    
    if [ "$DEBUG_MODE" = true ]; then
        show_debug_log "$session_dir"
    fi
    
    local state=$(get_state "$session_dir")
    if [ "$state" = "used" ]; then
        echo "Error: session '$session_id' is in use (state=used)" >&2
        echo "Use 'kugetsu stop $session_id' first" >&2
        exit 1
    fi
    
    if [ "$force" = true ]; then
        rm -rf "$session_dir"
        echo "Session '$session_id' deleted"
        return
    fi
    
    echo "Delete session '$session_id'? [y/N] "
    local reply
    read reply
    if [ "$reply" = "y" ] || [ "$reply" = "Y" ]; then
        rm -rf "$session_dir"
        echo "Session '$session_id' deleted"
    else
        echo "Aborted"
    fi
}

main() {
    if [ $# -eq 0 ]; then
        usage
        exit 1
    fi
    
    local command="$1"
    shift
    
    case "$command" in
        help|--help|-h)
            usage
            ;;
        start)
            cmd_start "$@"
            ;;
        list)
            cmd_list "$@"
            ;;
        resume)
            cmd_resume "$@"
            ;;
        stop)
            cmd_stop "$@"
            ;;
        destroy)
            cmd_destroy "$@"
            ;;
        *)
            echo "Error: unknown command '$command'" >&2
            usage
            exit 1
            ;;
    esac
}

main "$@"
