#!/bin/bash

# Universal GitHub User Removal Script
# Removes a specified user from all repositories matching a prefix pattern
# under a given username or organization

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 BOLD='\033[1m'
readonly NC='\033[0m' # No Color

# Global variables
GITHUB_TOKEN=""
ROOT_USER=""
USER_TO_REMOVE=""
REPO_PREFIX=""
DRY_RUN=false
VERBOSE=false

# Statistics
TOTAL_REPOS_FOUND=0
MATCHING_REPOS=0
COLLABORATOR_REPOS=0
SUCCESSFUL_REMOVALS=0
FAILED_REMOVALS=0
ALREADY_REMOVED=0

# 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_verbose() {
    if [[ "$VERBOSE" == "true" ]]; then
        echo -e "${CYAN}🔍 $1${NC}"
    fi
}

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

show_usage() {
    cat << EOF
${BOLD}GitHub User Removal Script${NC}

${YELLOW}Usage:${NC}
  $0 -t TOKEN -r ROOT_USER -u USER_TO_REMOVE -p REPO_PREFIX [OPTIONS]

${YELLOW}Required Parameters:${NC}
  -t, --token TOKEN           GitHub Personal Access Token
  -r, --root ROOT_USER        Root GitHub username or organization
  -u, --user USER_TO_REMOVE   Username to remove from repositories
  -p, --prefix REPO_PREFIX    Repository name prefix (use '*' for all repos)

${YELLOW}Optional Parameters:${NC}
  -d, --dry-run              Show what would be done without making changes
  -v, --verbose              Enable verbose logging
  -h, --help                 Show this help message

${YELLOW}Examples:${NC}
  # Remove user from all repositories starting with 'bytelyst-'
  $0 -t "\$GITHUB_TOKEN" -r "saravanakumardb" -u "i-ayushh18" -p "bytelyst-"

  # Remove user from all repositories (dry run)
  $0 -t "\$GITHUB_TOKEN" -r "myorg" -u "olduser" -p "*" --dry-run

  # Remove user with verbose output
  $0 -t "\$GITHUB_TOKEN" -r "myorg" -u "olduser" -p "project-" -v

${YELLOW}Repository Prefix Patterns:${NC}
  "bytelyst-"     - Matches repos starting with 'bytelyst-'
  "*api*"         - Matches repos containing 'api'
  "*"             - Matches all repositories
  "web-app"       - Matches repos starting with 'web-app'

EOF
}

# Parse command line arguments
parse_arguments() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -t|--token)
                GITHUB_TOKEN="$2"
                shift 2
                ;;
            -r|--root)
                ROOT_USER="$2"
                shift 2
                ;;
            -u|--user)
                USER_TO_REMOVE="$2"
                shift 2
                ;;
            -p|--prefix)
                REPO_PREFIX="$2"
                shift 2
                ;;
            -d|--dry-run)
                DRY_RUN=true
                shift
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            -h|--help)
                show_usage
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                show_usage
                exit 1
                ;;
        esac
    done
}

# Validate required parameters
validate_parameters() {
    local missing_params=()
    
    [[ -z "$GITHUB_TOKEN" ]] && missing_params+=("token (-t)")
    [[ -z "$ROOT_USER" ]] && missing_params+=("root user (-r)")
    [[ -z "$USER_TO_REMOVE" ]] && missing_params+=("user to remove (-u)")
    [[ -z "$REPO_PREFIX" ]] && missing_params+=("repository prefix (-p)")
    
    if [[ ${#missing_params[@]} -gt 0 ]]; then
        log_error "Missing required parameters: ${missing_params[*]}"
        echo ""
        show_usage
        exit 1
    fi
}

# Validate GitHub token
validate_token() {
    log_info "Validating GitHub token..."
    
    local response
    response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/user" 2>/dev/null)
    
    local login
    login=$(echo "$response" | jq -r '.login // empty' 2>/dev/null)
    
    if [[ -z "$login" ]]; then
        log_error "Invalid or expired GitHub token"
        log_error "Please ensure your token has 'repo' and 'admin:org' permissions"
        exit 1
    fi
    
    log_success "Token validated (authenticated as: $login)"
}

# Fetch all repositories for a user or organization
fetch_all_repos() {
    local owner="$1"
    local all_repos=()
    local page=1
    
    log_verbose "Fetching repositories for: $owner"
    
    while true; do
        local response
        response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
            "https://api.github.com/users/$owner/repos?per_page=100&page=$page&type=all" 2>/dev/null)
        
        # Check if response is valid JSON
        if ! echo "$response" | jq empty 2>/dev/null; then
            log_warning "Invalid response from GitHub API for page $page"
            break
        fi
        
        # Check for errors
        local error_message
        error_message=$(echo "$response" | jq -r '.message // empty' 2>/dev/null)
        if [[ -n "$error_message" ]]; then
            if [[ "$error_message" == "Not Found" ]]; then
                # Try as organization
                log_verbose "User not found, trying as organization..."
                response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
                    "https://api.github.com/orgs/$owner/repos?per_page=100&page=$page&type=all" 2>/dev/null)
                
                if ! echo "$response" | jq empty 2>/dev/null; then
                    log_error "Could not fetch repositories for '$owner' (not found as user or organization)"
                    exit 1
                fi
            else
                log_error "GitHub API error: $error_message"
                exit 1
            fi
        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
            if [[ -n "$repo" && "$repo" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
                all_repos+=("$repo")
                log_verbose "Found repository: $repo"
            fi
        done <<< "$repos"
        
        ((page++))
    done
    
    TOTAL_REPOS_FOUND=${#all_repos[@]}
    if [[ ${#all_repos[@]} -gt 0 ]]; then
        printf '%s\n' "${all_repos[@]}"
    fi
}

# Check if repository name matches prefix pattern
matches_prefix() {
    local repo_full_name="$1"
    local pattern="$2"
    local repo_name
    repo_name=$(basename "$repo_full_name")
    
    # Convert shell wildcard pattern to bash pattern
    case "$pattern" in
        "*")
            return 0  # Match all
            ;;
        *"*"*)
            # Pattern contains wildcards
            if [[ "$repo_name" == $pattern ]]; then
                return 0
            fi
            ;;
        *)
            # Simple prefix match
            if [[ "$repo_name" == "$pattern"* ]]; then
                return 0
            fi
            ;;
    esac
    
    return 1
}

# Check if user is a collaborator on a repository
is_collaborator() {
    local repo="$1"
    local user="$2"
    
    local response
    response=$(curl -s -w "%{http_code}" -H "Authorization: token $GITHUB_TOKEN" \
        "https://api.github.com/repos/$repo/collaborators/$user" 2>/dev/null)
    
    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_verbose "Access forbidden for $repo (insufficient permissions)"
            return 1
            ;;
        *)
            log_verbose "Failed to check collaboration status for $user on $repo (HTTP: $http_code)"
            return 1
            ;;
    esac
}

# Remove user from repository
remove_user_from_repo() {
    local repo="$1"
    local user="$2"
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] Would remove $user from $repo"
        return 0
    fi
    
    log_verbose "Removing $user 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" 2>/dev/null)
    
    local http_code="${response: -3}"
    
    case "$http_code" in
        204)
            log_success "Successfully removed $user from $repo"
            ((SUCCESSFUL_REMOVALS++))
            return 0
            ;;
        404)
            log_info "User $user was not a collaborator on $repo (already removed)"
            ((ALREADY_REMOVED++))
            return 0
            ;;
        *)
            log_error "Failed to remove $user from $repo (HTTP: $http_code)"
            ((FAILED_REMOVALS++))
            return 1
            ;;
    esac
}

# Show final summary
show_summary() {
    log_header "Operation Summary"
    
    echo -e "${BOLD}Repositories scanned:${NC} $TOTAL_REPOS_FOUND"
    echo -e "${BOLD}Repositories matching prefix:${NC} $MATCHING_REPOS"
    echo -e "${BOLD}Repositories where user was collaborator:${NC} $COLLABORATOR_REPOS"
    echo ""
    echo -e "${GREEN}Successful removals:${NC} $SUCCESSFUL_REMOVALS"
    echo -e "${YELLOW}Already removed:${NC} $ALREADY_REMOVED"
    echo -e "${RED}Failed removals:${NC} $FAILED_REMOVALS"
    
    if [[ $((SUCCESSFUL_REMOVALS + ALREADY_REMOVED + FAILED_REMOVALS)) -gt 0 ]]; then
        local success_rate=$((((SUCCESSFUL_REMOVALS + ALREADY_REMOVED) * 100) / (SUCCESSFUL_REMOVALS + ALREADY_REMOVED + FAILED_REMOVALS)))
        echo -e "${CYAN}Success rate:${NC} ${success_rate}%"
    fi
    
    if [[ "$DRY_RUN" == "true" ]]; then
        echo ""
        log_warning "This was a dry run - no actual changes were made"
        log_info "Run without --dry-run to perform the actual removals"
    fi
}

# Main execution function
main() {
    log_header "GitHub User Removal Script"
    
    # Parse and validate arguments
    parse_arguments "$@"
    validate_parameters
    
    # Show operation details
    log_info "Root user/organization: $ROOT_USER"
    log_info "User to remove: $USER_TO_REMOVE"
    log_info "Repository prefix: $REPO_PREFIX"
    if [[ "$DRY_RUN" == "true" ]]; then
        log_warning "DRY RUN MODE - No changes will be made"
    fi
    
    # Validate token
    validate_token
    
    # Fetch all repositories
    log_header "Repository Discovery"
    local repos_output
    repos_output=$(fetch_all_repos "$ROOT_USER")
    
    if [[ -z "$repos_output" ]]; then
        log_warning "No repositories found for '$ROOT_USER'"
        exit 0
    fi
    
    log_success "Found $TOTAL_REPOS_FOUND repositories"
    
    # Filter repositories by prefix
    log_header "Filtering Repositories"
    local matching_repos=()
    
    while IFS= read -r repo; do
        if [[ -n "$repo" ]] && matches_prefix "$repo" "$REPO_PREFIX"; then
            matching_repos+=("$repo")
            log_verbose "Matched: $repo"
        fi
    done <<< "$repos_output"
    
    MATCHING_REPOS=${#matching_repos[@]}
    
    if [[ $MATCHING_REPOS -eq 0 ]]; then
        log_warning "No repositories match the prefix pattern '$REPO_PREFIX'"
        log_info "Available repositories:"
        while IFS= read -r repo; do
            log_info "  • $(basename "$repo")"
        done <<< "$repos_output"
        exit 0
    fi
    
    log_success "Found $MATCHING_REPOS repositories matching prefix '$REPO_PREFIX'"
    
    # Check collaborator status and remove
    log_header "Processing Repositories"
    
    local current=0
    for repo in "${matching_repos[@]}"; do
        ((current++))
        printf "\r${CYAN}Progress: [%3d%%] %d/%d repositories processed${NC}" \
            $((current * 100 / MATCHING_REPOS)) "$current" "$MATCHING_REPOS"
        
        if is_collaborator "$repo" "$USER_TO_REMOVE"; then
            ((COLLABORATOR_REPOS++))
            echo # New line after progress
            remove_user_from_repo "$repo" "$USER_TO_REMOVE"
        fi
    done
    
    echo # New line after progress
    
    # Show final summary
    show_summary
    
    if [[ $FAILED_REMOVALS -gt 0 ]]; then
        exit 1
    else
        log_success "Operation completed successfully!"
        exit 0
    fi
}

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