#!/bin/bash

# bytelyst-cli.sh: Unified CLI for Bytelyst GitHub DevOps Tools
#
# Usage examples:
#   ./bytelyst-cli.sh list-public-repos --user <username>
#   ./bytelyst-cli.sh list-private-repos --org <orgname>
#   ./bytelyst-cli.sh check-collaborators --input input.json
#   ./bytelyst-cli.sh export --type repos --output repos.json
#
# If no arguments are given, an interactive menu is shown.

RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
RESET=$(tput sgr0)

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

# agent-queue delegates to the standalone tool (no GitHub token / jq / curl needed),
# so handle it BEFORE the GITHUB_TOKEN + required-tools gates below.
if [[ "${1:-}" == "agent-queue" || "${1:-}" == "aq" ]]; then
    shift
    exec "$CLI_DIR/agent-queue/agent-queue.sh" "$@"
fi

REQUIRED_TOOLS=(jq curl)

# Check for required tools
for tool in "${REQUIRED_TOOLS[@]}"; do
    if ! command -v $tool &>/dev/null; then
        echo "${RED}❌ Error: Required tool '$tool' is not installed. Please install it and try again.${RESET}"
        exit 1
    fi
done

# Load .env if present. `set -a` exports everything sourced; this safely handles
# quoted values and spaces, unlike `export $(grep ... | xargs)`.
if [[ -f .env ]]; then
    set -a
    # shellcheck disable=SC1091
    . ./.env
    set +a
fi

# Validate GITHUB_TOKEN (printf so the newline renders, unlike echo "...\n...")
if [[ -z "${GITHUB_TOKEN:-}" ]]; then
    printf '%s❌ Error: GITHUB_TOKEN is not set.\nSet it in your environment (e.g. export GITHUB_TOKEN=... in ~/.zshrc, ~/.bashrc, or .env).%s\n' "$RED" "$RESET" >&2
    exit 1
fi

# gh_get_all <url> -> echo one JSON array combining ALL pages (per_page=100).
# Verifies HTTP 200 on every page before parsing; returns non-zero on API error.
gh_get_all() {
    local base="$1" page=1 combined="[]"
    local joiner='&'; [[ "$base" == *'?'* ]] || joiner='?'
    while :; do
        local resp http body n
        resp=$(curl -sS -w $'\n%{http_code}' \
            -H "Authorization: token $GITHUB_TOKEN" \
            -H "Accept: application/vnd.github+json" \
            "${base}${joiner}per_page=100&page=${page}")
        http="${resp##*$'\n'}"
        body="${resp%$'\n'*}"
        if [[ "$http" != "200" ]]; then
            printf '%s❌ GitHub API error (HTTP %s) for %s%s\n' "$RED" "$http" "$base" "$RESET" >&2
            printf '%s' "$body" | jq -r '.message? // empty' >&2 2>/dev/null || true
            return 1
        fi
        n=$(printf '%s' "$body" | jq 'length' 2>/dev/null || echo 0)
        [[ "$n" -eq 0 ]] && break
        combined=$(jq -s 'add' <(printf '%s' "$combined") <(printf '%s' "$body"))
        [[ "$n" -lt 100 ]] && break
        page=$((page+1))
        [[ "$page" -gt 100 ]] && break
    done
    printf '%s' "$combined"
}

usage() {
    echo "${BLUE}Bytelyst CLI - Unified GitHub DevOps Tool${RESET}"
    echo ""
    echo "Usage: $0 <command> [options]"
    echo "Commands:"
    echo "  list-public-repos   --user <username>"
    echo "  list-private-repos  --org <orgname>"
    echo "  check-collaborators --input <input.json>"
    echo "  export              --type <repos|users> --output <file.json>"
    echo "  remove-user-from-all-repos --user <username> [--input <file.json>]"
    echo "  agent-queue (aq)    <init|add|run|status|watch|dash|stop|logs|requeue|clean> — agent prompt queue runner"
    echo "  help                Show this help message"
    echo ""
    echo "If no command is given, an interactive menu will be shown."
}

list_public_repos() {
    local user=""
    while [[ $# -gt 0 ]]; do
        case $1 in
            --user)
                user="$2"; shift 2;;
            *) shift;;
        esac
    done
    if [[ -z "$user" ]]; then
        echo "${RED}❌ Please provide --user <username>.${RESET}"; exit 1
    fi
    echo "${BLUE}🔍 Fetching all public repositories for user: $user...${RESET}"
    local json repos
    json=$(gh_get_all "https://api.github.com/users/$user/repos?type=public") || exit 1
    repos=$(printf '%s' "$json" | jq -r '.[].full_name')
    if [[ -z "$repos" ]]; then
        echo "${YELLOW}🚫 No public repositories found for user.${RESET}"
    else
        echo "$repos"
    fi
}

list_private_repos() {
    local org=""
    while [[ $# -gt 0 ]]; do
        case $1 in
            --org)
                org="$2"; shift 2;;
            *) shift;;
        esac
    done
    if [[ -z "$org" ]]; then
        echo "${RED}❌ Please provide --org <orgname>.${RESET}"; exit 1
    fi
    echo "${BLUE}🔍 Fetching all private repositories for org: $org...${RESET}"
    local json repos
    json=$(gh_get_all "https://api.github.com/orgs/$org/repos?type=private") || exit 1
    repos=$(printf '%s' "$json" | jq -r '.[].full_name')
    if [[ -z "$repos" ]]; then
        echo "${YELLOW}🚫 No private repositories found for org.${RESET}"
    else
        echo "$repos"
    fi
}

check_collaborators() {
    local input=""
    while [[ $# -gt 0 ]]; do
        case $1 in
            --input)
                input="$2"; shift 2;;
            *) shift;;
        esac
    done
    if [[ -z "$input" || ! -f "$input" ]]; then
        echo "${RED}❌ Please provide --input <input.json> (file must exist).${RESET}"; exit 1
    fi
    local org=$(jq -r '.org' "$input")
    local user=$(jq -r '.user' "$input")
    local whitelist=($(jq -r '.whitelist[]' "$input"))
    local repos=($(jq -r '.repos[]' "$input"))
    if [[ -z "$org" || -z "$user" || ${#whitelist[@]} -eq 0 || ${#repos[@]} -eq 0 ]]; then
        echo "${RED}❌ input.json must contain 'org', 'user', 'whitelist', and 'repos'.${RESET}"; exit 1
    fi
    for repo in "${repos[@]}"; do
        echo "${BLUE}🔍 Checking repo: $repo${RESET}"
        local cjson collaborators
        cjson=$(gh_get_all "https://api.github.com/repos/$org/$repo/collaborators") \
            || { echo "${YELLOW}⚠️ Skipping $repo (API error).${RESET}"; continue; }
        collaborators=$(printf '%s' "$cjson" | jq -r '.[].login')
        local non_whitelisted=()
        for collab in $collaborators; do
            # explicit membership test (avoids the array-concatenation pitfall of
            # [[ " ${whitelist[@]} " =~ " $collab " ]], which false-matches substrings)
            local is_white=false w
            for w in "${whitelist[@]}"; do
                [[ "$w" == "$collab" ]] && { is_white=true; break; }
            done
            $is_white || non_whitelisted+=("$collab")
        done
        if [[ ${#non_whitelisted[@]} -gt 0 ]]; then
            echo "${YELLOW}🚨 Repository: $repo${RESET}"
            echo "${RED}❌ Non-Whitelisted Collaborators:${RESET}"
            printf '%s\n' "${non_whitelisted[@]}"
            for user in "${non_whitelisted[@]}"; do
                read -p "Do you want to remove collaborator '$user' from '$repo'? (yes/no): " confirm
                if [[ "$confirm" == "yes" ]]; then
                    response=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$org/$repo/collaborators/$user")
                    if [[ "$response" -eq 204 ]]; then
                        echo "${GREEN}✅ Successfully removed $user from repository $repo.${RESET}"
                    else
                        echo "${YELLOW}⚠️ Failed to remove $user from repository $repo (HTTP Status: $response).${RESET}"
                    fi
                else
                    echo "${YELLOW}🚫 Skipped removal of $user from $repo.${RESET}"
                fi
            done
            echo "--------------------------------------------"
        fi
    done
}

export_json() {
    local type=""; local output=""
    while [[ $# -gt 0 ]]; do
        case $1 in
            --type)
                type="$2"; shift 2;;
            --output)
                output="$2"; shift 2;;
            *) shift;;
        esac
    done
    if [[ -z "$type" || -z "$output" ]]; then
        echo "${RED}❌ Please provide --type <repos|users> and --output <file.json>.${RESET}"; exit 1
    fi
    if [[ "$type" == "repos" ]]; then
        jq . repos.json > "$output"
        echo "${GREEN}✅ Exported repos to $output${RESET}"
    elif [[ "$type" == "users" ]]; then
        jq . users.json > "$output"
        echo "${GREEN}✅ Exported users to $output${RESET}"
    else
        echo "${RED}❌ Unknown export type: $type${RESET}"
        exit 1
    fi
}

remove_user_from_all_repos() {
    local user=""; local input="github_repos.json"
    while [[ $# -gt 0 ]]; do
        case $1 in
            --user)
                user="$2"; shift 2;;
            --input)
                input="$2"; shift 2;;
            *) shift;;
        esac
    done
    if [[ -z "$user" ]]; then
        echo "${RED}❌ Please provide --user <username>.${RESET}"; exit 1
    fi
    if [[ ! -f "$input" ]]; then
        echo "${RED}❌ Input file '$input' not found.${RESET}"; exit 1
    fi
    local org=$(jq -r '.org' "$input")
    local repos=($(jq -r '.repos[]' "$input"))
    if [[ -z "$org" || ${#repos[@]} -eq 0 ]]; then
        echo "${RED}❌ Input file must contain 'org' and 'repos'.${RESET}"; exit 1
    fi
    for repo in "${repos[@]}"; do
        echo "${BLUE}🔗 Removing user '$user' from repo: $repo${RESET}"
        response=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$org/$repo/collaborators/$user")
        if [[ "$response" -eq 204 ]]; then
            echo "${GREEN}✅ Successfully removed $user from $repo.${RESET}"
        elif [[ "$response" -eq 404 ]]; then
            echo "${YELLOW}⚠️ $user is not a collaborator on $repo or repo not found.${RESET}"
        else
            echo "${RED}❌ Failed to remove $user from $repo (HTTP Status: $response).${RESET}"
        fi
    done
}

interactive_menu() {
    echo "${BLUE}Bytelyst CLI Interactive Menu${RESET}"
    select opt in "List Public Repos" "List Private Repos" "Check Collaborators" "Export JSON" "Remove User from All Repos" "Agent Queue Status" "Exit"; do
        case $REPLY in
            1) read -p "Enter GitHub username: " user; list_public_repos --user "$user";;
            2) read -p "Enter GitHub org: " org; list_private_repos --org "$org";;
            3) read -p "Enter path to input.json: " input; check_collaborators --input "$input";;
            4) read -p "Export type (repos/users): " type; read -p "Output file: " output; export_json --type "$type" --output "$output";;
            5) read -p "Enter GitHub username: " user; remove_user_from_all_repos --user "$user";;
            6) "$CLI_DIR/agent-queue/agent-queue.sh" status;;
            7) exit 0;;
            *) echo "Invalid option.";;
        esac
    done
}

# Main CLI dispatcher
if [[ $# -eq 0 ]]; then
    interactive_menu
    exit 0
fi

case $1 in
    list-public-repos) shift; list_public_repos "$@";;
    list-private-repos) shift; list_private_repos "$@";;
    check-collaborators) shift; check_collaborators "$@";;
    export) shift; export_json "$@";;
    remove-user-from-all-repos) shift; remove_user_from_all_repos "$@";;
    agent-queue|aq) shift; exec "$CLI_DIR/agent-queue/agent-queue.sh" "$@";;
    help|--help|-h) usage;;
    *) echo "${RED}Unknown command: $1${RESET}"; usage; exit 1;;
esac 