#!/bin/bash

# Interactive User Removal Tool for GitHub Repositories
# Supports wildcard matching and handles both user and organization repositories

set -euo pipefail

# Color definitions
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly PURPLE='\033[0;35m'
readonly BOLD='\033[1m'
readonly NC='\033[0m' # No Color

# Global variables
GITHUB_TOKEN=""
ROOT_USER=""
USER_TO_REMOVE=""
REPO_PATTERN=""
CONFIRMATION_MODE="ask" # ask, yes_all, no_all
TOTAL_REPOS=0
PROCESSED_REPOS=0
SUCCESSFUL_REMOVALS=0
FAILED_REMOVALS=0
SKIPPED_REMOVALS=0
NON_INTERACTIVE=false

# Required tools
REQUIRED_TOOLS=(curl jq)

# Utility functions
log_info() {
    echo -e "${BLUE}ℹ️  $1${NC}"
}

log_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

log_warning() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

log_error() {
    echo -e "${RED}❌ $1${NC}"
}

log_progress() {
    echo -e "${CYAN}🔄 $1${NC}"
}

log_header() {
    echo -e "\n${BOLD}${PURPLE}$1${NC}"
    echo -e "${PURPLE}$(printf '=%.0s' {1..50})${NC}"
}

# Check required tools
check_dependencies() {
    log_header "Checking Dependencies"
    for tool in "${REQUIRED_TOOLS[@]}"; do
        if ! command -v "$tool" &>/dev/null; then
            log_error "Required tool '$tool' is not installed. Please install it and try again."
            exit 1
        fi
        log_success "$tool is available"
    done
}

# Input collection functions
collect_github_token() {
    log_header "GitHub Authentication"
    echo -e "${YELLOW}Enter your GitHub Personal Access Token:${NC}"
    echo -e "${CYAN}(Token needs 'repo' and 'admin:org' permissions)${NC}"
    read -s -r -p "Token: " GITHUB_TOKEN
    echo
    
    if [[ -z "$GITHUB_TOKEN" ]]; then
        log_error "GitHub token cannot be empty"
        exit 1
    fi
    
    # Validate token
    log_progress "Validating GitHub token..."
    local response
    response=$(curl -s -w "%{http_code}" -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user)
    local http_code="${response: -3}"
    
    if [[ "$http_code" != "200" ]]; then
        log_error "Invalid GitHub token or insufficient permissions (HTTP: $http_code)"
        if [[ "$http_code" == "401" ]]; then
            log_error "Token is invalid or expired"
        elif [[ "$http_code" == "403" ]]; then
            log_error "Token lacks required permissions (need 'repo' and 'admin:org')"
        fi
        exit 1
    fi
    
    # Get user info for confirmation
    local user_info
    user_info=$(echo "${response%???}" | jq -r '.login // "unknown"' 2>/dev/null)
    log_success "GitHub token validated successfully (authenticated as: $user_info)"
}

collect_root_user() {
    log_header "Root Account Information"
    echo -e "${YELLOW}Enter the root GitHub username/organization:${NC}"
    read -r -p "Root user: " ROOT_USER
    
    if [[ -z "$ROOT_USER" ]]; then
        log_error "Root user cannot be empty"
        exit 1
    fi
    
    log_success "Root user set to: $ROOT_USER"
}

collect_user_to_remove() {
    log_header "User Removal Target"
    echo -e "${YELLOW}Enter the username to remove from repositories:${NC}"
    read -r -p "User to remove: " USER_TO_REMOVE
    
    if [[ -z "$USER_TO_REMOVE" ]]; then
        log_error "User to remove cannot be empty"
        exit 1
    fi
    
    log_success "Target user: $USER_TO_REMOVE"
}

collect_repo_pattern() {
    log_header "Repository Pattern"
    echo -e "${YELLOW}Enter repository pattern (supports wildcards):${NC}"
    echo -e "${CYAN}Examples: *-go-api*, frontend-*, *-service, specific-repo${NC}"
    read -r -p "Repository pattern: " REPO_PATTERN
    
    if [[ -z "$REPO_PATTERN" ]]; then
        log_error "Repository pattern cannot be empty"
        exit 1
    fi
    
    log_success "Repository pattern: $REPO_PATTERN"
}

# GitHub API functions
fetch_user_repos() {
    local user="$1"
    local page=1
    local all_repos=()
    
    # Don't log here to avoid capturing log messages as repo names
    while true; do
        local response
        response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
            "https://api.github.com/users/$user/repos?per_page=100&page=$page&type=all")
        
        # Check if response is valid JSON and contains repositories
        if ! echo "$response" | jq empty 2>/dev/null; then
            log_error "Invalid JSON response from GitHub API"
            break
        fi
        
        # Check for authentication errors
        local error_message
        error_message=$(echo "$response" | jq -r '.message // empty' 2>/dev/null)
        if [[ "$error_message" == "Bad credentials" ]]; then
            log_error "GitHub token is invalid or expired"
            log_error "Please check your GITHUB_TOKEN environment variable"
            exit 1
        fi
        
        local repos
        repos=$(echo "$response" | jq -r '.[].full_name // empty' 2>/dev/null)
        
        if [[ -z "$repos" ]]; then
            break
        fi
        
        while IFS= read -r repo; do
            # Validate repository name format (should be owner/repo)
            if [[ "$repo" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
                all_repos+=("$repo")
            else
                log_warning "Skipping invalid repository name: $repo"
            fi
        done <<< "$repos"
        
        ((page++))
    done
    
    # Only print if there are repos to avoid unbound variable error
    if [[ ${#all_repos[@]} -gt 0 ]]; then
        printf '%s\n' "${all_repos[@]}"
    fi
}

fetch_org_repos() {
    local org="$1"
    local page=1
    local all_repos=()
    
    # Don't log here to avoid capturing log messages as repo names
    while true; do
        local response
        response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
            "https://api.github.com/orgs/$org/repos?per_page=100&page=$page&type=all")
        
        # Check if response is valid JSON and contains repositories
        if ! echo "$response" | jq empty 2>/dev/null; then
            log_error "Invalid JSON response from GitHub API for organization: $org"
            break
        fi
        
        # Check for authentication errors
        local error_message
        error_message=$(echo "$response" | jq -r '.message // empty' 2>/dev/null)
        if [[ "$error_message" == "Bad credentials" ]]; then
            log_error "GitHub token is invalid or expired"
            log_error "Please check your GITHUB_TOKEN environment variable"
            exit 1
        fi
        
        local repos
        repos=$(echo "$response" | jq -r '.[].full_name // empty' 2>/dev/null)
        
        if [[ -z "$repos" ]]; then
            break
        fi
        
        while IFS= read -r repo; do
            # Validate repository name format (should be owner/repo)
            if [[ "$repo" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
                all_repos+=("$repo")
            else
                log_warning "Skipping invalid repository name: $repo"
            fi
        done <<< "$repos"
        
        ((page++))
    done
    
    # Only print if there are repos to avoid unbound variable error
    if [[ ${#all_repos[@]} -gt 0 ]]; then
        printf '%s\n' "${all_repos[@]}"
    fi
}

fetch_user_orgs() {
    local user="$1"
    
    local response
    response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
        "https://api.github.com/users/$user/orgs")
    
    # Check if response is valid JSON
    if ! echo "$response" | jq empty 2>/dev/null; then
        log_error "Invalid JSON response from GitHub API for user organizations"
        log_error "Response: $response"
        return 1
    fi
    
    # Check for authentication errors
    local error_message
    error_message=$(echo "$response" | jq -r '.message // empty' 2>/dev/null)
    if [[ "$error_message" == "Bad credentials" ]]; then
        log_error "GitHub token is invalid or expired"
        log_error "Please check your GITHUB_TOKEN environment variable"
        exit 1
    fi
    
    # Check if response is an array
    local org_count
    org_count=$(echo "$response" | jq 'length' 2>/dev/null)
    
    if [[ "$org_count" == "0" ]] || [[ "$org_count" == "null" ]]; then
        return 0
    fi
    
    echo "$response" | jq -r '.[].login // empty' 2>/dev/null
}

# Check if user is a collaborator on a repository
check_user_collaboration() {
    local repo="$1"
    local user="$2"
    
    # Validate repository name format
    if [[ ! "$repo" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
        log_warning "Invalid repository name format: $repo"
        return 1
    fi
    
    local response
    response=$(curl -s -w "%{http_code}" -H "Authorization: token $GITHUB_TOKEN" \
        "https://api.github.com/repos/$repo/collaborators/$user")
    
    local http_code="${response: -3}"
    
    case "$http_code" in
        204)
            return 0  # User is a collaborator
            ;;
        404)
            return 1  # User is not a collaborator
            ;;
        403)
            log_warning "Access forbidden for $repo - may not have admin permissions"
            return 1
            ;;
        *)
            log_warning "Failed to check collaboration status for $user on $repo (HTTP: $http_code)"
            return 1
            ;;
    esac
}

# Get repositories where user is actually a collaborator
get_user_collaborations() {
    local repos=("$@")
    local user="$1"
    local collaborator_repos=()
    
    log_header "Checking User Collaborations"
    log_progress "Checking which repositories $user is actually a collaborator on..."
    
    local total=${#repos[@]}
    local checked=0
    
    for repo in "${repos[@]}"; do
        ((checked++))
        printf "\r${CYAN}Checking collaborations: [%3d%%] %d/%d repositories checked${NC}" \
            $((checked * 100 / total)) "$checked" "$total"
        
        if check_user_collaboration "$repo" "$user"; then
            collaborator_repos+=("$repo")
            log_info "✓ $user is a collaborator on $repo"
        fi
    done
    
    echo # New line after progress
    return 0
}

# Repository matching function
match_repo_pattern() {
    local repo_name="$1"
    local pattern="$2"
    
    # Convert shell wildcard pattern to regex
    local regex_pattern
    regex_pattern="${pattern//\*/.*}"
    
    if [[ "$repo_name" =~ $regex_pattern ]]; then
        return 0
    else
        return 1
    fi
}

# User confirmation functions
get_confirmation() {
    local repo="$1"
    local current="$2"
    local total="$3"
    
    case "$CONFIRMATION_MODE" in
        "yes_all")
            return 0
            ;;
        "no_all")
            return 1
            ;;
        "ask")
            echo -e "\n${YELLOW}[$current/$total] Remove user '$USER_TO_REMOVE' from '$repo'?${NC}"
            echo -e "${CYAN}Options: [y]es, [n]o, [a]ll yes, [q]uit, [s]kip all${NC}"
            read -p "Choice: " -n 1 -r choice
            echo
            
            case "$choice" in
                y|Y)
                    return 0
                    ;;
                n|N)
                    return 1
                    ;;
                a|A)
                    CONFIRMATION_MODE="yes_all"
                    log_info "Switched to 'yes to all' mode"
                    return 0
                    ;;
                s|S)
                    CONFIRMATION_MODE="no_all"
                    log_info "Switched to 'skip all' mode"
                    return 1
                    ;;
                q|Q)
                    log_warning "Operation cancelled by user"
                    exit 0
                    ;;
                *)
                    log_warning "Invalid choice, skipping..."
                    return 1
                    ;;
            esac
            ;;
    esac
}

# User removal function
remove_user_from_repo() {
    local repo="$1"
    
    log_progress "Removing $USER_TO_REMOVE from $repo..."
    
    local response
    response=$(curl -s -w "%{http_code}" -X DELETE \
        -H "Authorization: token $GITHUB_TOKEN" \
        "https://api.github.com/repos/$repo/collaborators/$USER_TO_REMOVE")
    
    local http_code="${response: -3}"
    
    case "$http_code" in
        204)
            log_success "Successfully removed $USER_TO_REMOVE from $repo"
            ((SUCCESSFUL_REMOVALS++))
            return 0
            ;;
        404)
            log_warning "$USER_TO_REMOVE is not a collaborator on $repo or repo not found"
            ((SKIPPED_REMOVALS++))
            return 1
            ;;
        *)
            log_error "Failed to remove $USER_TO_REMOVE from $repo (HTTP: $http_code)"
            ((FAILED_REMOVALS++))
            return 1
            ;;
    esac
}

# Progress display
show_progress() {
    local current="$1"
    local total="$2"
    local percentage=$((current * 100 / total))
    
    printf "\r${CYAN}Progress: [%3d%%] %d/%d repositories processed${NC}" "$percentage" "$current" "$total"
}

# Summary report
show_summary() {
    log_header "Operation Summary"
    echo -e "${BOLD}Total repositories processed: $PROCESSED_REPOS${NC}"
    echo -e "${GREEN}Successful removals: $SUCCESSFUL_REMOVALS${NC}"
    echo -e "${RED}Failed removals: $FAILED_REMOVALS${NC}"
    echo -e "${YELLOW}Skipped removals: $SKIPPED_REMOVALS${NC}"
    echo -e "${CYAN}Success rate: $(( SUCCESSFUL_REMOVALS * 100 / (SUCCESSFUL_REMOVALS + FAILED_REMOVALS + SKIPPED_REMOVALS) ))%${NC}"
}

# Parse command line arguments
parse_arguments() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -u|--user)
                USER_TO_REMOVE="$2"
                shift 2
                ;;
            -r|--root)
                ROOT_USER="$2"
                shift 2
                ;;
            -p|--pattern)
                REPO_PATTERN="$2"
                shift 2
                ;;
            -t|--token)
                GITHUB_TOKEN="$2"
                shift 2
                ;;
            --non-interactive)
                NON_INTERACTIVE=true
                CONFIRMATION_MODE="yes_all"
                shift
                ;;
            -h|--help)
                echo "Usage: $0 [OPTIONS]"
                echo "Options:"
                echo "  -u, --user USER        Username to remove from repositories"
                echo "  -r, --root USER        Root GitHub username/organization"
                echo "  -p, --pattern PATTERN  Repository pattern (supports wildcards)"
                echo "  -t, --token TOKEN      GitHub Personal Access Token"
                echo "  --non-interactive      Run without prompts (auto-confirm all)"
                echo "  -h, --help            Show this help message"
                echo ""
                echo "Example:"
                echo "  $0 -u i-ayushh18 -r saravanakumardb -p '*' -t \$GITHUB_TOKEN --non-interactive"
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                exit 1
                ;;
        esac
    done
}

# Main execution function
main() {
    log_header "GitHub User Removal Tool"
    
    # Parse command line arguments
    parse_arguments "$@"
    
    # Check dependencies
    check_dependencies
    
    # Collect inputs (interactive if not provided via command line)
    if [[ -z "$GITHUB_TOKEN" ]]; then
        collect_github_token
    else
        log_success "Using GitHub token from command line"
    fi
    
    if [[ -z "$ROOT_USER" ]]; then
        collect_root_user
    else
        log_success "Root user: $ROOT_USER"
    fi
    
    if [[ -z "$USER_TO_REMOVE" ]]; then
        collect_user_to_remove
    else
        log_success "Target user: $USER_TO_REMOVE"
    fi
    
    if [[ -z "$REPO_PATTERN" ]]; then
        collect_repo_pattern
    else
        log_success "Repository pattern: $REPO_PATTERN"
    fi
    
    # Collect all repositories
    log_header "Repository Discovery"
    local all_repos=()
    
    # Fetch root user repositories
    log_info "Fetching repositories for user: $ROOT_USER"
    local user_repos_output
    user_repos_output=$(fetch_user_repos "$ROOT_USER")
    local user_repos_exit_code=$?
    
    log_info "User repos fetch exit code: $user_repos_exit_code"
    log_info "User repos output: '$user_repos_output'"
    
    if [[ -n "$user_repos_output" ]]; then
        while IFS= read -r repo; do
            if [[ -n "$repo" ]] && [[ "$repo" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
                all_repos+=("$repo")
                log_info "Found user repo: $repo"
            elif [[ -n "$repo" ]]; then
                log_warning "Skipping invalid repository name: $repo"
            fi
        done <<< "$user_repos_output"
    else
        log_info "No repositories found for user: $ROOT_USER"
    fi
    
    # Fetch organization repositories
    log_info "Fetching organizations for user: $ROOT_USER"
    local orgs=()
    local org_output
    org_output=$(fetch_user_orgs "$ROOT_USER")
    local org_exit_code=$?
    
    log_info "Organization fetch exit code: $org_exit_code"
    log_info "Organization output: '$org_output'"
    
    if [[ $org_exit_code -eq 0 ]] && [[ -n "$org_output" ]]; then
        while IFS= read -r org; do
            if [[ -n "$org" ]] && [[ "$org" =~ ^[a-zA-Z0-9._-]+$ ]]; then
                orgs+=("$org")
                log_info "Found organization: $org"
            elif [[ -n "$org" ]]; then
                log_warning "Skipping invalid organization name: $org"
            fi
        done <<< "$org_output"
    else
        log_info "No organizations found for user: $ROOT_USER"
    fi
    
    # Fetch repositories for each organization
    if [[ ${#orgs[@]} -gt 0 ]]; then
        for org in "${orgs[@]}"; do
            log_info "Fetching repositories for organization: $org"
            while IFS= read -r repo; do
                if [[ -n "$repo" ]] && [[ "$repo" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
                    all_repos+=("$repo")
                    log_info "Found org repo: $repo"
                elif [[ -n "$repo" ]]; then
                    log_warning "Skipping invalid repository name: $repo"
                fi
            done < <(fetch_org_repos "$org")
        done
    fi
    
    # Filter repositories by pattern
    log_header "Repository Filtering"
    local matching_repos=()
    
    log_info "Total repositories found: ${#all_repos[@]}"
    
    for repo in "${all_repos[@]}"; do
        local repo_name
        repo_name=$(basename "$repo")
        
        if match_repo_pattern "$repo_name" "$REPO_PATTERN"; then
            matching_repos+=("$repo")
            log_info "Matched: $repo"
        fi
    done
    
    TOTAL_REPOS=${#matching_repos[@]}
    
    if [[ $TOTAL_REPOS -eq 0 ]]; then
        log_warning "No repositories match the pattern '$REPO_PATTERN'"
        log_info "Available repositories:"
        for repo in "${all_repos[@]}"; do
            log_info "  • $repo"
        done
        exit 0
    fi
    
    log_success "Found $TOTAL_REPOS matching repositories"
    
    # Check which repositories the user is actually a collaborator on
    log_header "Checking User Collaborations"
    log_progress "Checking which repositories '$USER_TO_REMOVE' is actually a collaborator on..."
    
    local collaborator_repos=()
    local checked=0
    
    for repo in "${matching_repos[@]}"; do
        ((checked++))
        printf "\r${CYAN}Checking collaborations: [%3d%%] %d/%d repositories checked${NC}" \
            $((checked * 100 / TOTAL_REPOS)) "$checked" "$TOTAL_REPOS"
        
        if check_user_collaboration "$repo" "$USER_TO_REMOVE"; then
            collaborator_repos+=("$repo")
        fi
    done
    
    echo # New line after progress
    
    local collaborator_count=${#collaborator_repos[@]}
    
    if [[ $collaborator_count -eq 0 ]]; then
        log_warning "User '$USER_TO_REMOVE' is not a collaborator on any of the $TOTAL_REPOS matching repositories"
        log_info "No action needed - user is already not a collaborator on any matching repositories"
        exit 0
    fi
    
    log_success "User '$USER_TO_REMOVE' is a collaborator on $collaborator_count out of $TOTAL_REPOS matching repositories"
    
    # Show preview of repositories where user will be removed
    log_header "Preview: Repositories where '$USER_TO_REMOVE' will be removed"
    for repo in "${collaborator_repos[@]}"; do
        log_info "• $repo"
    done
    
    # Confirmation before proceeding
    if [[ "$NON_INTERACTIVE" == "false" ]]; then
        echo -e "\n${YELLOW}About to remove user '$USER_TO_REMOVE' from $collaborator_count repositories${NC}"
        read -p "Continue? [y/N]: " -n 1 -r
        echo
        
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            log_warning "Operation cancelled"
            exit 0
        fi
    else
        log_info "Non-interactive mode: proceeding with removal from $collaborator_count repositories"
    fi
    
    # Process repositories
    log_header "User Removal Process"
    
    for repo in "${collaborator_repos[@]}"; do
        ((PROCESSED_REPOS++))
        
        show_progress "$PROCESSED_REPOS" "$collaborator_count"
        
        if get_confirmation "$repo" "$PROCESSED_REPOS" "$collaborator_count"; then
            remove_user_from_repo "$repo"
        else
            log_info "Skipped: $repo"
            ((SKIPPED_REMOVALS++))
        fi
    done
    
    echo # New line after progress
    
    # Show final summary
    show_summary
    
    log_success "Operation completed successfully!"
}

# Script execution
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi