#!/bin/bash
# gantt-tasks library - Full CRUD for Gantt Board tasks
# Location: ~/.agents/skills/gantt-tasks/lib/tasks.sh
# Refactored to use API endpoints with machine token auth

# Configuration
GANTT_API_URL="${GANTT_API_URL:-https://gantt-board.twisteddevices.com/api}"
GANTT_MACHINE_TOKEN="${GANTT_MACHINE_TOKEN:-}"
MAX_ID="9c29cc99-81a1-4e75-8dff-cd7cc5ceb5aa"  # Max user ID

# Debug function
debug() {
    echo "[DEBUG] $*" >&2
}

# Error handler
error_exit() {
    echo "❌ $1" >&2
    return 1
}

# Make API call with machine token
_api_call() {
    local method="$1"
    local endpoint="$2"
    local data="${3:-}"
    
    if [[ -z "$GANTT_MACHINE_TOKEN" ]]; then
        error_exit "GANTT_MACHINE_TOKEN not set"
        return 1
    fi
    
    local url="${GANTT_API_URL}${endpoint}"
    local curl_opts=(
        -s
        -H "Content-Type: application/json"
        -H "Authorization: Bearer ${GANTT_MACHINE_TOKEN}"
    )
    
    if [[ -n "$data" ]]; then
        curl_opts+=(-d "$data")
    fi
    
    curl "${curl_opts[@]}" -X "$method" "$url" 2>/dev/null
}

# Resolve project name to ID
resolve_project_id() {
    local PROJECT_NAME="$1"
    
    # Special case: Research Project
    if [[ "$PROJECT_NAME" == "Research" || "$PROJECT_NAME" == "Research Project" ]]; then
        echo "a1b2c3d4-0003-0000-0000-000000000003"
        return 0
    fi
    
    # Query by name via API
    local RESULT=$(_api_call "GET" "/projects" | jq -r --arg q "$PROJECT_NAME" '
        .projects
        | map(select((.name // "") | ascii_downcase | contains($q | ascii_downcase)))
        | .[0].id // empty
    ')
    
    if [[ -n "$RESULT" ]]; then
        echo "$RESULT"
        return 0
    fi
    
    # Return empty if not found
    echo ""
    return 1
}

# Resolve user name to ID
resolve_user_id() {
    local USER_NAME="$1"
    
    # Current mappings
    case "$USER_NAME" in
        "Max"|"max") echo "9c29cc99-81a1-4e75-8dff-cd7cc5ceb5aa" ;;
        "Matt"|"matt"|"Matt Bruce") echo "0a3e400c-3932-48ae-9b65-f3f9c6f26fe9" ;;
        *) echo "$MAX_ID" ;;  # Default to Max
    esac
}

# Get current sprint (contains today's date)
sprint_get_current() {
    local TODAY=$(date +%Y-%m-%d)
    
    # Get current sprint via API
    local RESULT=$(_api_call "GET" "/sprints" | jq -r --arg today "$TODAY" '
        .sprints
        | map(select(.startDate <= $today and .endDate >= $today))
        | .[0].id // empty
    ')
    
    if [[ -n "$RESULT" && "$RESULT" != "null" ]]; then
        echo "$RESULT"
        return 0
    fi
    
    # Fallback: get most recent sprint
    RESULT=$(_api_call "GET" "/sprints" | jq -r '
        .sprints
        | sort_by(.startDate)
        | reverse
        | .[0].id // empty
    ')
    
    echo "$RESULT"
}

# Resolve sprint name/ID
resolve_sprint_id() {
    local SPRINT="$1"
    
    if [[ "$SPRINT" == "current" ]]; then
        sprint_get_current
        return 0
    fi
    
    # If it looks like a UUID, use it directly
    if [[ "$SPRINT" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]]; then
        echo "$SPRINT"
        return 0
    fi
    
    # Query by name via API
    local RESULT=$(_api_call "GET" "/sprints" | jq -r --arg q "$SPRINT" '
        .sprints
        | map(select((.name // "") | ascii_downcase | contains($q | ascii_downcase)))
        | .[0].id // empty
    ')
    
    echo "$RESULT"
}

# Create a new task
task_create() {
    local TITLE=""
    local DESCRIPTION=""
    local TYPE="task"
    local STATUS="open"
    local PRIORITY="medium"
    local PROJECT=""
    local SPRINT=""
    local ASSIGNEE="Max"
    local DUE_DATE=""
    local TAGS=""
    
    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            --title) TITLE="$2"; shift 2 ;;
            --description) DESCRIPTION="$2"; shift 2 ;;
            --type) TYPE="$2"; shift 2 ;;
            --status) STATUS="$2"; shift 2 ;;
            --priority) PRIORITY="$2"; shift 2 ;;
            --project) PROJECT="$2"; shift 2 ;;
            --sprint) SPRINT="$2"; shift 2 ;;
            --assignee) ASSIGNEE="$2"; shift 2 ;;
            --due-date) DUE_DATE="$2"; shift 2 ;;
            --tags) TAGS="$2"; shift 2 ;;
            *) shift ;;
        esac
    done
    
    # Validate
    [[ -z "$TITLE" ]] && error_exit "--title is required" && return 1
    
    # Resolve IDs
    local PROJECT_ID="a1b2c3d4-0003-0000-0000-000000000003"
    if [[ -n "$PROJECT" ]]; then
        PROJECT_ID=$(resolve_project_id "$PROJECT")
    fi
    
    local SPRINT_ID=""
    if [[ -n "$SPRINT" ]]; then
        SPRINT_ID=$(resolve_sprint_id "$SPRINT")
    fi
    
    local ASSIGNEE_ID=$(resolve_user_id "$ASSIGNEE")
    
    # Build JSON payload
    local JSONPayload=$(jq -n \
        --arg title "$TITLE" \
        --arg type "$TYPE" \
        --arg status "$STATUS" \
        --arg priority "$PRIORITY" \
        --arg assigneeId "$ASSIGNEE_ID" \
        --arg projectId "$PROJECT_ID" \
        '{
            title: $title,
            type: $type,
            status: $status,
            priority: $priority,
            assigneeId: $assigneeId,
            projectId: $projectId,
            comments: [],
            tags: []
        }')
    
    # Add optional fields
    [[ -n "$DESCRIPTION" ]] && JSONPayload=$(echo "$JSONPayload" | jq --arg desc "$DESCRIPTION" '. + {description: $desc}')
    [[ -n "$SPRINT_ID" ]] && JSONPayload=$(echo "$JSONPayload" | jq --arg sid "$SPRINT_ID" '. + {sprintId: $sid}')
    [[ -n "$DUE_DATE" ]] && JSONPayload=$(echo "$JSONPayload" | jq --arg dd "$DUE_DATE" '. + {dueDate: $dd}')
    [[ -n "$TAGS" ]] && JSONPayload=$(echo "$JSONPayload" | jq --argjson tags "[$(echo "$TAGS" | sed 's/,/","/g' | sed 's/^/"/' | sed 's/$/"/')]" '. + {tags: $tags}')
    
    # Create task via API
    local Response=$(_api_call "POST" "/tasks" "{\"task\": $JSONPayload}")
    
    local TaskId=$(echo "$Response" | jq -r '.task.id // .id // empty')
    
    if [[ -n "$TaskId" && "$TaskId" != "null" ]]; then
        echo "$TaskId"
        return 0
    fi
    
    error_exit "Failed to create task: $(echo "$Response" | jq -r '.error // "Unknown error"')"
    return 1
}

# Get task details
task_get() {
    local TASK_ID="$1"
    
    local Response=$(_api_call "GET" "/tasks")
    echo "$Response" | jq --arg id "$TASK_ID" '.tasks | map(select(.id == $id)) | .[0] // empty'
}

# List tasks with filters
task_list() {
    local StatusFilter=""
    local ProjectFilter=""
    local SprintFilter=""
    local AssigneeFilter=""
    local PriorityFilter=""
    local JsonOutput=false
    
    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            --status) StatusFilter="$2"; shift 2 ;;
            --project) ProjectFilter="$2"; shift 2 ;;
            --sprint) SprintFilter="$2"; shift 2 ;;
            --assignee) AssigneeFilter="$2"; shift 2 ;;
            --priority) PriorityFilter="$2"; shift 2 ;;
            --json) JsonOutput=true; shift ;;
            *) shift ;;
        esac
    done
    
    # Get all tasks via API
    local Response=$(_api_call "GET" "/tasks")
    local Tasks=$(echo "$Response" | jq '.tasks // []')
    
    # Apply filters in jq
    local Filtered="$Tasks"
    
    if [[ -n "$StatusFilter" ]]; then
        # Handle comma-separated status values
        if [[ "$StatusFilter" =~ , ]]; then
            Filtered=$(echo "$Filtered" | jq --arg statuses "$StatusFilter" '
                [split(",")] as $statusList | map(select(.status as $s | $statusList | index($s)))
            ')
        else
            Filtered=$(echo "$Filtered" | jq --arg status "$StatusFilter" 'map(select(.status == $status))')
        fi
    fi
    
    if [[ -n "$ProjectFilter" ]]; then
        local ProjectId=$(resolve_project_id "$ProjectFilter")
        [[ -n "$ProjectId" ]] && Filtered=$(echo "$Filtered" | jq --arg pid "$ProjectId" 'map(select(.projectId == $pid))')
    fi
    
    if [[ -n "$SprintFilter" ]]; then
        local SprintId=$(resolve_sprint_id "$SprintFilter")
        [[ -n "$SprintId" ]] && Filtered=$(echo "$Filtered" | jq --arg sid "$SprintId" 'map(select(.sprintId == $sid))')
    fi
    
    if [[ -n "$AssigneeFilter" ]]; then
        local AssigneeId=$(resolve_user_id "$AssigneeFilter")
        Filtered=$(echo "$Filtered" | jq --arg aid "$AssigneeId" 'map(select(.assigneeId == $aid))')
    fi
    
    if [[ -n "$PriorityFilter" ]]; then
        Filtered=$(echo "$Filtered" | jq --arg pri "$PriorityFilter" 'map(select(.priority == $pri))')
    fi
    
    if [[ "$JsonOutput" == true ]]; then
        echo "{\"tasks\": $Filtered}"
    else
        # Pretty print
        echo "$Filtered" | jq -r '.[] | "\(.status) | \(.priority) | \(.title) | \(.id)"' 2>/dev/null
    fi
}

# Update task
task_update() {
    local TASK_ID="$1"
    shift
    
    # First get the current task
    local CurrentTask=$(task_get "$TASK_ID")
    [[ -z "$CurrentTask" ]] && error_exit "Task not found: $TASK_ID" && return 1
    
    # Build updates
    local Updates="{}"
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            --title) Updates=$(echo "$Updates" | jq --arg v "$2" '. + {title: $v}'); shift 2 ;;
            --description) Updates=$(echo "$Updates" | jq --arg v "$2" '. + {description: $v}'); shift 2 ;;
            --status) Updates=$(echo "$Updates" | jq --arg v "$2" '. + {status: $v}'); shift 2 ;;
            --priority) Updates=$(echo "$Updates" | jq --arg v "$2" '. + {priority: $v}'); shift 2 ;;
            --due-date) Updates=$(echo "$Updates" | jq --arg v "$2" '. + {dueDate: $v}'); shift 2 ;;
            *) shift ;;
        esac
    done
    
    # Merge current task with updates
    local MergedTask=$(echo "$CurrentTask" | jq --argjson updates "$Updates" '. + $updates')
    
    # Send update via API
    local Payload=$(jq -n --argjson task "$MergedTask" '{task: $task}')
    local Response=$(_api_call "POST" "/tasks" "$Payload")
    
    if echo "$Response" | jq -e '.error' >/dev/null 2>&1; then
        error_exit "Update failed: $(echo "$Response" | jq -r '.error')"
        return 1
    fi
    
    echo "✅ Task updated"
}

# Delete task
task_delete() {
    local TASK_ID="$1"
    
    _api_call "DELETE" "/tasks" "{\"id\": \"$TASK_ID\"}" >/dev/null
    
    echo "✅ Task deleted"
}

# Add comment to task
task_add_comment() {
    local TASK_ID="$1"
    local TEXT="$2"
    local UseChecklist=false
    local StatusPrefix=""
    
    shift 2
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            --checklist) UseChecklist=true; shift ;;
            --status) StatusPrefix="$2"; shift 2 ;;
            *) shift ;;
        esac
    done
    
    # Format comment
    local Now=$(date +"%Y-%m-%d %H:%M")
    local StatusEmoji="🔄"
    [[ -n "$StatusPrefix" ]] && StatusEmoji="$StatusPrefix"
    
    local CommentText
    if [[ "$UseChecklist" == true ]]; then
        CommentText=$(cat <<EOF
## [$Now] $StatusEmoji ${StatusPrefix:-Update}

### ✅ Completed
- [x] Previous work

### 🔄 In Progress
- [x] $TEXT

### 📋 Remaining
- [ ] Next step

### 📊 Progress: 1/1 tasks
EOF
)
    else
        CommentText="[$Now] $TEXT"
    fi
    
    # Get current task with comments
    local CurrentTask=$(task_get "$TASK_ID")
    local CurrentComments=$(echo "$CurrentTask" | jq '.comments // []')
    
    # Build new comment
    local NewComment=$(jq -n \
        --arg id "$(uuidgen 2>/dev/null || date +%s)" \
        --arg text "$CommentText" \
        --arg author "$MAX_ID" \
        '{
            id: $id,
            text: $text,
            createdAt: now | todate,
            commentAuthorId: $author,
            replies: []
        }')
    
    # Append to comments
    local UpdatedComments=$(echo "$CurrentComments" | jq --argjson new "$NewComment" '. + [$new]')
    
    # Merge and update task
    local MergedTask=$(echo "$CurrentTask" | jq --argjson comments "$UpdatedComments" '. + {comments: $comments}')
    local Payload=$(jq -n --argjson task "$MergedTask" '{task: $task}')
    
    _api_call "POST" "/tasks" "$Payload" >/dev/null
    
    echo "✅ Comment added"
}

# Attach file to task (stores content in attachments field)
task_attach_file() {
    local TASK_ID="$1"
    local FILE_PATH="$2"
    local Description="${3:-Attached file}"
    
    [[ ! -f "$FILE_PATH" ]] && error_exit "File not found: $FILE_PATH" && return 1
    
    # Read file content
    local Content=$(cat "$FILE_PATH")
    local FileName=$(basename "$FILE_PATH")
    
    # Get current task with attachments
    local CurrentTask=$(task_get "$TASK_ID")
    local CurrentAttachments=$(echo "$CurrentTask" | jq '.attachments // []')
    
    # Build new attachment
    local NewAttachment=$(jq -n \
        --arg id "$(uuidgen 2>/dev/null || date +%s)" \
        --arg name "$FileName" \
        --arg type "$(file -b --mime-type "$FILE_PATH" 2>/dev/null || echo 'application/octet-stream')" \
        --arg dataUrl "data:text/plain;base64,$(base64 -i "$FILE_PATH" | tr -d '\n')" \
        '{
            id: $id,
            name: $name,
            type: $type,
            dataUrl: $dataUrl,
            uploadedAt: now | todate
        }')
    
    # Append to attachments
    local UpdatedAttachments=$(echo "$CurrentAttachments" | jq --argjson new "$NewAttachment" '. + [$new]')
    
    # Merge and update task
    local MergedTask=$(echo "$CurrentTask" | jq --argjson attachments "$UpdatedAttachments" '. + {attachments: $attachments}')
    local Payload=$(jq -n --argjson task "$MergedTask" '{task: $task}')
    
    _api_call "POST" "/tasks" "$Payload" >/dev/null
    
    echo "✅ File attached: $FileName"
}

# Update an existing comment by ID
task_update_comment() {
    local TASK_ID="$1"
    local COMMENT_ID="$2"
    local NEW_TEXT="$3"
    
    # Get current task
    local CurrentTask=$(task_get "$TASK_ID")
    local AllComments=$(echo "$CurrentTask" | jq '.comments // []')
    
    # Find and update the specific comment, keep others unchanged
    local UpdatedComments=$(echo "$AllComments" | jq --arg cid "$COMMENT_ID" --arg text "$NEW_TEXT" \
        'map(if .id == $cid then .text = $text else . end)')
    
    # Merge and update task
    local MergedTask=$(echo "$CurrentTask" | jq --argjson comments "$UpdatedComments" '. + {comments: $comments}')
    local Payload=$(jq -n --argjson task "$MergedTask" '{task: $task}')
    
    _api_call "POST" "/tasks" "$Payload" >/dev/null
    
    echo "✅ Comment updated"
}

# Export all functions
export -f resolve_project_id
export -f resolve_user_id
export -f sprint_get_current
export -f resolve_sprint_id
export -f task_create
export -f task_get
export -f task_list
export -f task_update
export -f task_delete
export -f task_add_comment
export -f task_update_comment
export -f task_attach_file
export -f _api_call
