#!/bin/bash
# Common Launchpad API Workflow Functions
# Source this file to use these functions in your scripts

# Check if lp-api is available
if ! command -v lp-api &> /dev/null; then
    echo "Error: lp-api command not found. Download it from https://github.com/fourdollars/lp-api/releases or install with: go install github.com/fourdollars/lp-api@latest"
    exit 1
fi

# Wrapper to handle config file
_lp_api_exec() {
    local conf="${LP_API_CONF:-./.lp-api.toml}"
    if [ -f "$conf" ]; then
        lp-api -conf "$conf" "$@"
    else
        lp-api "$@"
    fi
}

# ============================================================================
# BUG WORKFLOWS
# ============================================================================

# Get bug details in human-readable format
# Usage: lp_bug_info <bug-id>
lp_bug_info() {
    local bug_id=$1
    _lp_api_exec get "bugs/${bug_id}" | jq '{
        id: .id,
        title: .title,
        status: .status,
        importance: .importance,
        tags: .tags,
        created: .date_created,
        web_link: .web_link
    }'
}

# Search bugs with common filters
# Usage: lp_search_bugs <project> [status] [importance] [tags...]
lp_search_bugs() {
    local project=$1
    local status=${2:-""}
    local importance=${3:-""}
    shift $(( $# < 3 ? $# : 3 ))
    local tags=("$@")
    
    local cmd="_lp_api_exec get $project ws.op==searchTasks"
    [ -n "$status" ] && cmd="$cmd status==$status"
    [ -n "$importance" ] && cmd="$cmd importance==$importance"
    
    for tag in "${tags[@]}"; do
        cmd="$cmd tags==$tag"
    done
    
    [ ${#tags[@]} -gt 1 ] && cmd="$cmd tags_combinator==All"
    
    eval "$cmd"
}

# Count bugs matching criteria
# Usage: lp_count_bugs <project> [status] [importance] [tags...]
lp_count_bugs() {
    local project=$1
    local status=${2:-""}
    local importance=${3:-""}
    shift $(( $# < 3 ? $# : 3 ))
    local tags=("$@")
    
    local cmd="_lp_api_exec get $project ws.op==searchTasks ws.show==total_size"
    [ -n "$status" ] && cmd="$cmd status==$status"
    [ -n "$importance" ] && cmd="$cmd importance==$importance"
    
    for tag in "${tags[@]}"; do
        cmd="$cmd tags==$tag"
    done
    
    eval "$cmd"
}

# Add comment to bug
# Usage: lp_bug_comment <bug-id> <message>
lp_bug_comment() {
    local bug_id=$1
    local message=$2
    _lp_api_exec post "bugs/${bug_id}" ws.op=newMessage content="$message"
}

# Update bug tags
# Usage: lp_bug_update_tags <bug-id> <tag1> [tag2] [tag3]...
lp_bug_update_tags() {
    local bug_id=$1
    shift
    local tags=("$@")
    
    # Convert to JSON array
    local json_tags
    json_tags=$(printf '%s\n' "${tags[@]}" | jq -R . | jq -s .)
    
    _lp_api_exec patch "bugs/${bug_id}" "tags:=${json_tags}"
}

# Subscribe to bug
# Usage: lp_bug_subscribe <bug-id> [person-uri]
lp_bug_subscribe() {
    local bug_id=$1
    local person=$2
    
    if [ -z "$person" ]; then
        # Fetch current user info and extract self_link
        # We don't use lp_get_field here to avoid circular dependency if it were more complex
        person=$(_lp_api_exec get people/+me | jq -r .self_link)
    fi
    
    _lp_api_exec post "bugs/${bug_id}" ws.op=subscribe person="$person"
}

# Check if a bug has a specific tag
# Usage: lp_bug_has_tag <bug-id> <tag>
lp_bug_has_tag() {
    local bug_id=$1
    local tag=$2
    _lp_api_exec get "bugs/${bug_id}" | jq -r --arg tag "$tag" 'any(.tags[]; . == $tag)'
}

# Get status of a bug task for a specific target
# Usage: lp_bug_task_status <bug-id> <target-name>
lp_bug_task_status() {
    local bug_id=$1
    local target=$2
    _lp_api_exec get "bugs/${bug_id}" | \
        _lp_api_exec .bug_tasks_collection_link | \
        jq -r --arg target "$target" '.entries[] | select(.bug_target_name == $target) | .status'
}

# Get all tasks for a bug
# Usage: lp_get_bug_tasks <bug-id>
lp_get_bug_tasks() {
    local bug_id=$1
    _lp_api_exec get "bugs/${bug_id}" | \
        _lp_api_exec .bug_tasks_collection_link | \
        jq -r '.entries[] | "\(.bug_target_name): \(.status)"'
}

# ============================================================================
# BUILD WORKFLOWS
# ============================================================================

# Get latest build for a livefs
# Usage: lp_latest_build <livefs-path>
# Example: lp_latest_build "~ubuntu-cdimage/+livefs/ubuntu/jammy/ubuntu"
lp_latest_build() {
    local livefs=$1
    _lp_api_exec get "$livefs" | \
        _lp_api_exec .builds_collection_link | \
        jq -r '.entries[0]'
}

# Get build status
# Usage: lp_build_status <build-resource-path>
lp_build_status() {
    local build=$1
    _lp_api_exec get "$build" | jq -r '.buildstate'
}

# Download all artifacts from a build
# Usage: lp_download_build_artifacts <build-resource-path>
lp_download_build_artifacts() {
    local build=$1
    
    echo "Getting artifact URLs for $build..."
    local urls
    urls=$(_lp_api_exec get "$build" ws.op==getFileUrls | jq -r '.[]')
    
    if [ -z "$urls" ]; then
        echo "No artifacts found for build"
        return 1
    fi
    
    echo "Downloading artifacts..."
    while IFS= read -r url; do
        echo "Downloading: $(basename "$url")"
        _lp_api_exec download "$url"
    done <<< "$urls"
}

# Wait for build to complete
# Usage: lp_wait_for_build <build-resource-path> [timeout-seconds]
lp_wait_for_build() {
    local build=$1
    local timeout=${2:-3600}  # Default 1 hour
    local elapsed=0
    local interval=30
    
    echo "Waiting for build to complete: $build"
    
    while [ "$elapsed" -lt "$timeout" ]; do
        local state
        state=$(lp_build_status "$build")
        echo "[$elapsed s] Build state: $state"
        
        case "$state" in
            "Successfully built")
                echo "Build completed successfully!"
                return 0
                ;;
            "Failed to build"|"Cancelled build"|"Build for superseded Source")
                echo "Build failed with state: $state"
                return 1
                ;;
            *)
                sleep $interval
                elapsed=$((elapsed + interval))
                ;;
        esac
    done
    
    echo "Timeout waiting for build"
    return 1
}

# Get failed builds from livefs
# Usage: lp_failed_builds <livefs-path>
lp_failed_builds() {
    local livefs=$1
    _lp_api_exec get "$livefs" | \
        _lp_api_exec .builds_collection_link | \
        jq -r '.entries[] | select(.buildstate == "Failed to build") | .self_link'
}

# ============================================================================
# PACKAGE WORKFLOWS
# ============================================================================

# Get source package info
# Usage: lp_package_info <distro> <series> <package-name>
lp_package_info() {
    local distro=$1
    local series=$2
    local package=$3
    _lp_api_exec get "${distro}/${series}/+source/${package}"
}

# Search package bugs
# Usage: lp_package_bugs <distro> <package-name> [status]
lp_package_bugs() {
    local distro=$1
    local package=$2
    local status=${3:-""}
    
    local cmd="_lp_api_exec get ${distro}/+source/${package} ws.op==searchTasks"
    [ -n "$status" ] && cmd="$cmd status==$status"
    
    eval "$cmd"
}

# Check package uploads in a series
# Usage: lp_check_package_uploads <distro> <series> <package-name>
lp_check_package_uploads() {
    local distro=$1
    local series=$2
    local package=$3
    
    _lp_api_exec get "${distro}/${series}" \
        ws.op==getPackageUploads \
        name=="$package" \
        ws.show==total_size
}

# ============================================================================
# PACKAGE SET WORKFLOWS
# ============================================================================

# Get sources in a package set
# Usage: lp_get_package_set_sources <distro> <series> <package-set-name>
lp_get_package_set_sources() {
    local distro=$1
    local series=$2
    local pkgset=$3
    
    _lp_api_exec get "package-sets/${distro}/${series}/${pkgset}" \
        ws.op==getSourcesIncluded | \
        jq -r 'if type == "array" then .[] else .entries[] end'
}

# ============================================================================
# PPA WORKFLOWS
# ============================================================================

# List PPA packages
# Usage: lp_ppa_packages <owner> <ppa-name>
lp_ppa_packages() {
    local owner=$1
    local ppa=$2
    _lp_api_exec get "~${owner}/+archive/ubuntu/${ppa}" | \
        _lp_api_exec .published_sources_collection_link | \
        jq -r '.entries[] | "\(.source_package_name) \(.source_package_version)"'
}

# Copy package to PPA
# Usage: lp_ppa_copy_package <dest-owner> <dest-ppa> <source-name> <version> <from-archive> <to-series>
lp_ppa_copy_package() {
    local owner=$1
    local ppa=$2
    local pkg=$3
    local version=$4
    local from=$5
    local series=$6
    
    _lp_api_exec post "~${owner}/+archive/ubuntu/${ppa}" \
        ws.op=copyPackage \
        source_name="$pkg" \
        version="$version" \
        from_archive="$from" \
        to_pocket=Release \
        to_series="$series"
}

# ============================================================================
# PERSON/TEAM WORKFLOWS
# ============================================================================

# Get person info
# Usage: lp_person_info <username>
lp_person_info() {
    local username=$1
    _lp_api_exec get "~${username}" | jq '{
        name: .name,
        display_name: .display_name,
        karma: .karma,
        is_team: .is_team,
        web_link: .web_link
    }'
}

# Get team members
# Usage: lp_team_members <team-name>
lp_team_members() {
    local team=$1
    _lp_api_exec get "~${team}" | \
        _lp_api_exec .members_collection_link | \
        jq -r '.entries[] | .name'
}

# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================

# Follow a link field from piped JSON
# Usage: lp-api get resource | lp_follow_link <field-name>
lp_follow_link() {
    local field=$1
    _lp_api_exec ".${field}"
}

# Get a single field from a resource
# Usage: lp_get_field <resource> <field-name>
lp_get_field() {
    local resource=$1
    local field=$2
    _lp_api_exec get "$resource" | jq -r ".${field}"
}

# List all series for a project
# Usage: lp_list_series [project-name]
lp_list_series() {
    local project=${1:-"ubuntu"}
    
    # Check for required tools
    if ! command -v jq &> /dev/null; then
        echo "Error: jq is required for lp_list_series. Please install it."
        return 1
    fi
    
    # Verify project exists and get series collection link
    local series_link
    series_link=$(_lp_api_exec get "$project" | _lp_api_exec .series_collection_link 2>/dev/null)
    if [ -z "$series_link" ] || [ "$series_link" == "null" ]; then
        echo "Error: Could not find series for project '$project'"
        return 1
    fi
    
    (
        echo -e "Series\tStatus\tWeb Link"
        echo -e "------\t------\t--------"
        
        _lp_api_exec get "$project" | \
            _lp_api_exec .series_collection_link | \
            jq -r '.entries[] | "\((.displayname // .display_name) + (if .version then " (\(.version))" else "" end))\t\(.status)\t\(.web_link)"'
    ) | column -t -s $'\t'
}

# Pretty print JSON from lp-api
# Usage: lp-api get resource | lp_pretty
lp_pretty() {
    jq '.'
}

# Extract web links from search results
# Usage: lp-api get project ws.op==searchTasks | lp_extract_web_links
lp_extract_web_links() {
    jq -r '.entries[] | .web_link'
}

# Extract all *_link fields from a resource
# Usage: lp-api get resource | lp_show_links
lp_show_links() {
    jq 'to_entries | .[] | select(.key | endswith("_link")) | {(.key): .value}'
}

# Paginate through all results
# Usage: lp_paginate_all <resource> <operation> [filters...]
lp_paginate_all() {
    local resource=$1
    local operation=$2
    shift 2
    local filters=("$@")
    
    local start=0
    local size=100
    local has_more=true
    
    while [ "$has_more" = true ]; do
        local cmd="_lp_api_exec get $resource ws.op==$operation ws.start==$start ws.size==$size"
        for filter in "${filters[@]}"; do
            cmd="$cmd $filter"
        done
        
        local result
        result=$(eval "$cmd")
        local entries
        entries=$(echo "$result" | jq '.entries')
        local count
        count=$(echo "$entries" | jq 'length')
        
        if [ "$count" -eq 0 ]; then
            has_more=false
        else
            echo "$entries" | jq -c '.[]'
            start=$((start + size))
        fi
    done
}

# ============================================================================
# EXAMPLE WORKFLOWS
# ============================================================================

# Example: Monitor builds for a livefs
example_monitor_builds() {
    local series=${1:-"noble"}
    local livefs="~ubuntu-cdimage/+livefs/ubuntu/${series}/ubuntu"
    
    echo "=== Latest Build for ${series} ==="
    lp_latest_build "$livefs" | jq '{
        id: .id,
        state: .buildstate,
        started: .date_started,
        web_link: .web_link
    }'
    
    echo -e "\n=== Failed Builds ==="
    lp_failed_builds "$livefs"
}

# Example: Bug triage workflow
example_bug_triage() {
    local project="ubuntu"
    
    echo "=== High Priority Untriaged Bugs ==="
    lp_search_bugs "$project" "New" "High" | \
        lp_extract_web_links | head -10
    
    echo -e "\n=== Bug Count by Status ==="
    for status in "New" "Triaged" "In Progress" "Fix Committed"; do
        count=$(lp_count_bugs "$project" "$status")
        printf "%-15s: %d\n" "$status" "$count"
    done
}

# Example: Download latest Ubuntu artifacts
example_download_latest_ubuntu() {
    local series=${1:-"noble"}
    local livefs="~ubuntu-cdimage/+livefs/ubuntu/${series}/ubuntu"
    
    echo "Getting latest build for ${series}..."
    local build_link
    build_link=$(lp_latest_build "$livefs" | jq -r '.self_link')
    
    echo "Build: $build_link"
    
    local state
    state=$(lp_build_status "$build_link")
    echo "State: $state"
    
    if [ "$state" = "Successfully built" ]; then
        lp_download_build_artifacts "$build_link"
    else
        echo "Build not ready for download"
        exit 1
    fi
}

# Print usage if script is executed directly
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
    cat << 'EOF'
Launchpad API Workflow Functions

Usage: source this file in your scripts
    source common-workflows.sh

Description:
  This script provides a collection of shell functions to interact with the
  Launchpad API using the '_lp_api_exec' tool. It simplifies common tasks like
  bug management, build monitoring, and package queries.

Available Functions:

  [Bug Workflows]
  lp_bug_info <bug-id>
      Get details (ID, title, status, tags, etc.) for a specific bug.
  lp_search_bugs <project> [status] [importance] [tags...]
      Search bugs in a project. Status/Importance are optional (use "" to skip).
  lp_count_bugs <project> [status] [importance] [tags...]
      Get the total count of bugs matching the criteria.
  lp_bug_comment <bug-id> <message>
      Post a new comment to a bug.
  lp_bug_update_tags <bug-id> <tag1> [tag2]...
      Replace all tags on a bug with the provided list.
  lp_bug_subscribe <bug-id> [person-uri]
      Subscribe a user (default: self) to a bug.
  lp_bug_has_tag <bug-id> <tag>
      Check if a bug has a specific tag (returns true/false).
  lp_bug_task_status <bug-id> <target-name>
      Get the status of a task for a specific target (e.g. "ubuntu").
  lp_get_bug_tasks <bug-id>
      List all tasks and their statuses for a bug.

  [Build Workflows]
  lp_latest_build <livefs-path>
      Get the most recent build for a LiveFS.
  lp_build_status <build-resource-path>
      Get the current state of a build (e.g. "Successfully built").
  lp_download_build_artifacts <build-resource-path>
      Download all files associated with a build.
  lp_wait_for_build <build-resource-path> [timeout-seconds]
      Poll a build until it completes or times out.
  lp_failed_builds <livefs-path>
      List links to failed builds for a LiveFS.

  [Package Workflows]
  lp_package_info <distro> <series> <package-name>
      Get source package details for a specific series.
  lp_package_bugs <distro> <package-name> [status]
      Search for bugs related to a source package.
  lp_check_package_uploads <distro> <series> <package-name>
      Count upload records for a package in a series.

  [Package Set Workflows]
  lp_get_package_set_sources <distro> <series> <package-set-name>
      List source packages included in a package set.

  [PPA Workflows]
  lp_ppa_packages <owner> <ppa-name>
      List packages published in a PPA.
  lp_ppa_copy_package <dest-owner> <dest-ppa> <source-name> <version> <from-archive> <to-series>
      Copy a package from one archive to a PPA.

  [Person/Team Workflows]
  lp_person_info <username>
      Get public profile info for a person or team.
  lp_team_members <team-name>
      List active members of a team.

  [Utility Functions]
  lp_follow_link <field-name>
      Read JSON from stdin and fetch the resource URL in <field-name>.
  lp_get_field <resource> <field-name>
      Fetch a resource and extract a specific field.
  lp_list_series [project-name]
      List all series (releases) for a project (default: ubuntu).
  lp_pretty
      Format JSON output (alias for `jq '.'`).
  lp_extract_web_links
      Extract 'web_link' fields from a JSON list of entries.
  lp_show_links
      Show all fields ending in '_link' from a resource.
  lp_paginate_all <resource> <operation> [filters...]
      Fetch ALL results for a paginated collection (handles pagination automatically).

  [Example Workflows]
  example_monitor_builds [series]
      Show latest and failed builds for Ubuntu (default: noble).
  example_bug_triage
      Demonstrate searching and counting bugs for triage.
  example_download_latest_ubuntu [series]
      Download artifacts from the latest Ubuntu LiveFS build (default: noble).

Examples:
  # Search for 'New' and 'High' priority bugs in Ubuntu with tags
  lp_search_bugs ubuntu "New" "High" focal jammy

  # Download artifacts from a specific build
  lp_download_build_artifacts "~ubuntu-cdimage/+livefs/ubuntu/noble/ubuntu/+build/12345"

  # List all series for Cloud-Init
  lp_list_series cloud-init

EOF
fi
