#!/bin/bash
# Task CLI for Gantt Board (API passthrough)
# Usage: ./task.sh [list|get|create|update|delete|current-sprint|bulk-create] [args...]

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=./lib/api_client.sh
source "$SCRIPT_DIR/lib/api_client.sh"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log_info() { echo -e "${BLUE}i${NC} $1"; }
log_success() { echo -e "${GREEN}ok${NC} $1"; }
log_warning() { echo -e "${YELLOW}warn${NC} $1"; }
log_error() { echo -e "${RED}error${NC} $1"; }

UUID_PATTERN='^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
DEFAULT_PROJECT_ID="${DEFAULT_PROJECT_ID:-}"
DEFAULT_ASSIGNEE_ID="${DEFAULT_ASSIGNEE_ID:-}"

check_dependencies() {
  if ! command -v jq >/dev/null 2>&1; then
    log_error "jq is required. Install with: brew install jq"
    exit 1
  fi
  if ! command -v uuidgen >/dev/null 2>&1; then
    log_error "uuidgen is required"
    exit 1
  fi
}

show_usage() {
  cat << 'USAGE'
Task CLI for Gantt Board

USAGE:
  ./task.sh [list|get|create|update|delete|current-sprint|bulk-create] [args...]

COMMANDS:
  list [status]                      List tasks (supports filters)
  get <task-id>                      Get specific task
  create "Title" [status] [priority] [project] [assignee] [sprint] [type]
  create --title "Title" [flags...]  Create task using flags
  update <task-id> <field> <value>   Update one field (legacy)
  update <task-id> [flags...]        Update task with flags
  delete <task-id>                   Delete task
  current-sprint                 Show current sprint ID
  bulk-create <json-file>            Bulk create from JSON array
USAGE
}

resolve_project_id() {
  local identifier="$1"

  if [[ -z "$identifier" ]]; then
    if [[ -n "$DEFAULT_PROJECT_ID" ]]; then
      echo "$DEFAULT_PROJECT_ID"
      return 0
    fi
    local response
    response=$(api_call GET "/projects")
    echo "$response" | jq -r '.projects[0].id // empty'
    return 0
  fi

  if [[ "$identifier" =~ $UUID_PATTERN ]]; then
    echo "$identifier"
    return 0
  fi

  local response
  response=$(api_call GET "/projects")
  local project_id
  project_id=$(echo "$response" | jq -r --arg q "$identifier" '
    .projects
    | map(select((.name // "") | ascii_downcase | contains($q | ascii_downcase)))
    | .[0].id // empty
  ')

  if [[ -n "$project_id" ]]; then
    echo "$project_id"
    return 0
  fi

  log_error "Project '$identifier' not found"
  return 1
}

resolve_assignee_id() {
  local identifier="$1"

  if [[ -z "$identifier" ]]; then
    if [[ -n "$DEFAULT_ASSIGNEE_ID" ]]; then
      echo "$DEFAULT_ASSIGNEE_ID"
    else
      echo ""
    fi
    return 0
  fi

  if [[ "$identifier" =~ $UUID_PATTERN ]]; then
    echo "$identifier"
    return 0
  fi

  local response
  response=$(api_call GET "/auth/users")
  local user_id
  user_id=$(echo "$response" | jq -r --arg q "$identifier" '
    .users
    | map(select(
        ((.name // "") | ascii_downcase | contains($q | ascii_downcase))
        or ((.email // "") | ascii_downcase == ($q | ascii_downcase))
      ))
    | .[0].id // empty
  ')

  if [[ -n "$user_id" ]]; then
    echo "$user_id"
    return 0
  fi

  log_error "Assignee '$identifier' not found"
  return 1
}

resolve_sprint_id() {
  local identifier="$1"

  if [[ -z "$identifier" ]]; then
    echo ""
    return 0
  fi

  if [[ "$identifier" == "current" ]]; then
    local response
    response=$(api_call GET "/sprints/current")
    echo "$response" | jq -r '.sprint.id // empty'
    return 0
  fi

  if [[ "$identifier" =~ $UUID_PATTERN ]]; then
    echo "$identifier"
    return 0
  fi

  local response
  response=$(api_call GET "/sprints")
  local sprint_id
  sprint_id=$(echo "$response" | jq -r --arg q "$identifier" '
    .sprints
    | map(select((.name // "") | ascii_downcase | contains($q | ascii_downcase)))
    | .[0].id // empty
  ')

  if [[ -n "$sprint_id" ]]; then
    echo "$sprint_id"
    return 0
  fi

  log_error "Sprint '$identifier' not found"
  return 1
}

get_current_sprint() {
  local response
  response=$(api_call GET "/sprints/current")
  echo "$response" | jq -r '.sprint.id // empty'
}

to_tag_array() {
  local tags_csv="$1"
  if [[ -z "$tags_csv" ]]; then
    echo '[]'
    return
  fi
  jq -cn --arg csv "$tags_csv" '$csv | split(",") | map(gsub("^\\s+|\\s+$"; "")) | map(select(length > 0))'
}

to_comment_array() {
  local comment_text="$1"
  if [[ -z "$comment_text" ]]; then
    echo '[]'
    return
  fi
  local now
  now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
  jq -cn --arg id "$(date +%s)-$RANDOM" --arg text "$comment_text" --arg createdAt "$now" '
    [{ id: $id, text: $text, createdAt: $createdAt, commentAuthorId: "assistant", replies: [] }]
  '
}

list_tasks() {
  local positional_status="${1:-}"
  local status_filter=""
  local priority_filter=""
  local project_filter=""
  local assignee_filter=""
  local type_filter=""
  local limit=""
  local output_json=false

  if [[ -n "$positional_status" && "$positional_status" != --* ]]; then
    status_filter="$positional_status"
    shift || true
  fi

  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --status) status_filter="${2:-}"; shift 2 ;;
      --priority) priority_filter="${2:-}"; shift 2 ;;
      --project) project_filter="${2:-}"; shift 2 ;;
      --assignee) assignee_filter="${2:-}"; shift 2 ;;
      --type) type_filter="${2:-}"; shift 2 ;;
      --limit) limit="${2:-}"; shift 2 ;;
      --json) output_json=true; shift ;;
      *) shift ;;
    esac
  done

  local response
  response=$(api_call GET "/tasks?scope=active-sprint")

  local tasks
  tasks=$(echo "$response" | jq '.tasks')

  if [[ -n "$status_filter" ]]; then
    tasks=$(echo "$tasks" | jq --arg v "$status_filter" '
      ($v | split(",") | map(gsub("^\\s+|\\s+$"; "")) | map(select(length > 0))) as $statuses
      | map(select(.status as $s | ($statuses | index($s))))
    ')
  fi
  if [[ -n "$priority_filter" ]]; then
    tasks=$(echo "$tasks" | jq --arg v "$priority_filter" 'map(select(.priority == $v))')
  fi
  if [[ -n "$type_filter" ]]; then
    tasks=$(echo "$tasks" | jq --arg v "$type_filter" 'map(select(.type == $v))')
  fi
  if [[ -n "$project_filter" ]]; then
    local project_id
    project_id=$(resolve_project_id "$project_filter")
    tasks=$(echo "$tasks" | jq --arg v "$project_id" 'map(select(.projectId == $v))')
  fi
  if [[ -n "$assignee_filter" ]]; then
    local assignee_id
    assignee_id=$(resolve_assignee_id "$assignee_filter")
    tasks=$(echo "$tasks" | jq --arg v "$assignee_id" 'map(select(.assigneeId == $v))')
  fi
  if [[ -n "$limit" ]]; then
    tasks=$(echo "$tasks" | jq --argjson n "$limit" '.[0:$n]')
  fi

  if [[ "$output_json" == true ]]; then
    echo "$tasks" | jq .
    return
  fi

  local count
  count=$(echo "$tasks" | jq 'length')
  if [[ "$count" -eq 0 ]]; then
    local current_sprint_id
    current_sprint_id="$(get_current_sprint 2>/dev/null || true)"
    if [[ -z "$current_sprint_id" ]]; then
      log_warning "No current sprint found. Returning 0 tasks."
    fi
  fi
  log_success "Found $count task(s)"

  printf "%-36s %-34s %-12s %-10s\n" "ID" "TITLE" "STATUS" "PRIORITY"
  printf "%-36s %-34s %-12s %-10s\n" "------------------------------------" "----------------------------------" "------------" "----------"

  echo "$tasks" | jq -r '.[] | [.id, (.title // "" | tostring | .[0:32]), (.status // ""), (.priority // "")] | @tsv' \
    | while IFS=$'\t' read -r id title status priority; do
        printf "%-36s %-34s %-12s %-10s\n" "$id" "$title" "$status" "$priority"
      done
}

get_task() {
  local task_id="${1:-}"
  if [[ -z "$task_id" ]]; then
    log_error "Task ID required"
    exit 1
  fi

  local response
  response=$(api_call GET "/tasks?taskId=$(urlencode "$task_id")&include=detail")
  echo "$response" | jq '.tasks[0]'
}

create_from_payload() {
  local task_payload="$1"
  api_call POST "/tasks" "{\"task\": $task_payload}" | jq .
}

create_task() {
  local title=""
  local description=""
  local task_type="task"
  local status="open"
  local priority="medium"
  local project=""
  local sprint=""
  local assignee=""
  local due_date=""
  local tags_csv=""
  local comments_text=""
  local file_input=""

  if [[ $# -gt 0 && "${1:-}" != --* ]]; then
    # Legacy positional form
    title="${1:-}"
    status="${2:-$status}"
    priority="${3:-$priority}"
    project="${4:-$project}"
    assignee="${5:-$assignee}"
    sprint="${6:-$sprint}"
    task_type="${7:-$task_type}"
  fi

  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --title) title="${2:-}"; shift 2 ;;
      --description) description="${2:-}"; shift 2 ;;
      --type) task_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_csv="${2:-}"; shift 2 ;;
      --comments) comments_text="${2:-}"; shift 2 ;;
      --file) file_input="${2:-}"; shift 2 ;;
      --interactive)
        log_error "Interactive mode is not supported in API passthrough mode"
        exit 1
        ;;
      *) shift ;;
    esac
  done

  if [[ -n "$file_input" ]]; then
    if [[ ! -f "$file_input" ]]; then
      log_error "File not found: $file_input"
      exit 1
    fi
    title=$(jq -r '.title // ""' "$file_input")
    description=$(jq -r '.description // ""' "$file_input")
    task_type=$(jq -r '.type // "task"' "$file_input")
    status=$(jq -r '.status // "open"' "$file_input")
    priority=$(jq -r '.priority // "medium"' "$file_input")
    project=$(jq -r '.project // ""' "$file_input")
    sprint=$(jq -r '.sprint // ""' "$file_input")
    assignee=$(jq -r '.assignee // ""' "$file_input")
    due_date=$(jq -r '.due_date // ""' "$file_input")
    tags_csv=$(jq -r '.tags // ""' "$file_input")
    comments_text=$(jq -r '.comments // ""' "$file_input")
  fi

  if [[ -z "$title" ]]; then
    log_error "Title is required"
    exit 1
  fi

  local project_id
  project_id=$(resolve_project_id "$project")
  if [[ -z "$project_id" ]]; then
    log_error "Could not resolve project"
    exit 1
  fi

  local assignee_id
  assignee_id=$(resolve_assignee_id "$assignee")

  local sprint_id
  sprint_id=$(resolve_sprint_id "$sprint")

  local tags_json
  tags_json=$(to_tag_array "$tags_csv")

  local comments_json
  comments_json=$(to_comment_array "$comments_text")

  local task_id
  task_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
  local now
  now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

  local task_payload
  task_payload=$(jq -n \
    --arg id "$task_id" \
    --arg title "$title" \
    --arg description "$description" \
    --arg type "$task_type" \
    --arg status "$status" \
    --arg priority "$priority" \
    --arg projectId "$project_id" \
    --arg sprintId "$sprint_id" \
    --arg assigneeId "$assignee_id" \
    --arg dueDate "$due_date" \
    --arg createdAt "$now" \
    --arg updatedAt "$now" \
    --argjson tags "$tags_json" \
    --argjson comments "$comments_json" \
    '{
      id: $id,
      title: $title,
      description: (if $description == "" then null else $description end),
      type: $type,
      status: $status,
      priority: $priority,
      projectId: $projectId,
      sprintId: (if $sprintId == "" then null else $sprintId end),
      assigneeId: (if $assigneeId == "" then null else $assigneeId end),
      dueDate: (if $dueDate == "" then null else $dueDate end),
      createdAt: $createdAt,
      updatedAt: $updatedAt,
      tags: $tags,
      comments: $comments,
      attachments: []
    }')

  create_from_payload "$task_payload"
}

update_task() {
  local task_id="${1:-}"
  shift || true

  if [[ -z "$task_id" ]]; then
    log_error "Task ID required"
    exit 1
  fi

  local existing
  existing=$(api_call GET "/tasks?taskId=$(urlencode "$task_id")&include=detail" | jq '.tasks[0]')

  if [[ "$existing" == "null" || -z "$existing" ]]; then
    log_error "Task not found: $task_id"
    exit 1
  fi

  if [[ $# -ge 2 && "${1:-}" != --* ]]; then
    local field="${1:-}"
    local value="${2:-}"
    existing=$(echo "$existing" | jq --arg f "$field" --arg v "$value" '. + {($f): $v}')
    shift 2 || true
  fi

  local add_comment=""
  local clear_tags=false
  local set_tags=""

  while [[ $# -gt 0 ]]; do
    case "${1:-}" in
      --status) existing=$(echo "$existing" | jq --arg v "${2:-}" '.status = $v'); shift 2 ;;
      --priority) existing=$(echo "$existing" | jq --arg v "${2:-}" '.priority = $v'); shift 2 ;;
      --title) existing=$(echo "$existing" | jq --arg v "${2:-}" '.title = $v'); shift 2 ;;
      --description) existing=$(echo "$existing" | jq --arg v "${2:-}" '.description = $v'); shift 2 ;;
      --type) existing=$(echo "$existing" | jq --arg v "${2:-}" '.type = $v'); shift 2 ;;
      --project)
        local project_id
        project_id=$(resolve_project_id "${2:-}")
        existing=$(echo "$existing" | jq --arg v "$project_id" '.projectId = $v')
        shift 2
        ;;
      --assignee)
        local assignee_id
        assignee_id=$(resolve_assignee_id "${2:-}")
        existing=$(echo "$existing" | jq --arg v "$assignee_id" '.assigneeId = (if $v == "" then null else $v end)')
        shift 2
        ;;
      --sprint)
        local sprint_input="${2:-}"
        local sprint_id
        sprint_id=$(resolve_sprint_id "$sprint_input")
        existing=$(echo "$existing" | jq --arg v "$sprint_id" '.sprintId = (if $v == "" then null else $v end)')
        shift 2
        ;;
      --due-date) existing=$(echo "$existing" | jq --arg v "${2:-}" '.dueDate = (if $v == "" then null else $v end)'); shift 2 ;;
      --add-comment) add_comment="${2:-}"; shift 2 ;;
      --clear-tags) clear_tags=true; shift ;;
      --tags) set_tags="${2:-}"; shift 2 ;;
      *) shift ;;
    esac
  done

  if [[ "$clear_tags" == true ]]; then
    existing=$(echo "$existing" | jq '.tags = []')
  fi

  if [[ -n "$set_tags" ]]; then
    local tags_json
    tags_json=$(to_tag_array "$set_tags")
    existing=$(echo "$existing" | jq --argjson tags "$tags_json" '.tags = $tags')
  fi

  if [[ -n "$add_comment" ]]; then
    local comment
    comment=$(to_comment_array "$add_comment" | jq '.[0]')
    existing=$(echo "$existing" | jq --argjson c "$comment" '.comments = (.comments // []) + [$c]')
  fi

  api_call POST "/tasks" "{\"task\": $existing}" | jq .
}

delete_task() {
  local task_id="${1:-}"
  if [[ -z "$task_id" ]]; then
    log_error "Task ID required"
    exit 1
  fi
  api_call DELETE "/tasks" "{\"id\": \"$task_id\"}" | jq .
}

bulk_create() {
  local file="${1:-}"
  if [[ -z "$file" || ! -f "$file" ]]; then
    log_error "bulk-create requires a valid JSON file"
    exit 1
  fi

  jq -c '.[]' "$file" | while IFS= read -r row; do
    local title
    title=$(echo "$row" | jq -r '.title // empty')
    if [[ -z "$title" ]]; then
      log_warning "Skipping entry without title"
      continue
    fi

    local task_type status priority project sprint assignee due_date tags comments description
    task_type=$(echo "$row" | jq -r '.type // "task"')
    status=$(echo "$row" | jq -r '.status // "open"')
    priority=$(echo "$row" | jq -r '.priority // "medium"')
    project=$(echo "$row" | jq -r '.project // ""')
    sprint=$(echo "$row" | jq -r '.sprint // ""')
    assignee=$(echo "$row" | jq -r '.assignee // ""')
    due_date=$(echo "$row" | jq -r '.due_date // ""')
    tags=$(echo "$row" | jq -r '.tags // ""')
    comments=$(echo "$row" | jq -r '.comments // ""')
    description=$(echo "$row" | jq -r '.description // ""')

    create_task \
      --title "$title" \
      --description "$description" \
      --type "$task_type" \
      --status "$status" \
      --priority "$priority" \
      --project "$project" \
      --sprint "$sprint" \
      --assignee "$assignee" \
      --due-date "$due_date" \
      --tags "$tags" \
      --comments "$comments"
  done
}

check_dependencies

case "${1:-}" in
  list)
    shift
    list_tasks "$@"
    ;;
  get)
    get_task "${2:-}"
    ;;
  create)
    shift
    create_task "$@"
    ;;
  update)
    shift
    update_task "$@"
    ;;
  delete)
    delete_task "${2:-}"
    ;;
  current-sprint)
    shift
    get_current_sprint
    ;;
  bulk-create)
    shift
    bulk_create "${1:-}"
    ;;
  help|--help|-h|"")
    show_usage
    ;;
  *)
    log_error "Unknown command: ${1:-}"
    show_usage
    exit 1
    ;;
esac
