#!/bin/sh

set -eu

VERSION="0.0.1-20250509"
PROXIFIER_DIR="${HOME}/.freeleaps/proxifier"

help() {
    echo "Freeleaps Cluster Proxifier (Version: ${VERSION})"
    echo ""
    echo "This script helps you to forward Kubernetes service ports to your local machine."
    echo "It maintains the forwarding state and provides commands to manage port forwarding."
    echo ""
    echo "Usage: freeleaps-cluster-proxifier <sub-command>"
    echo ""
    echo "Sub Commands:"
    echo "    forward,-f,--forward <namespace>/<service> -p <local-port>:<service-port>    Forward a service port to local"
    echo "    stop,-s,--stop <namespace>/<service>                                         Stop forwarding a service"
    echo "    list,-l,--list                                                               List all forwarded services"
    echo "    list-available,-la,--list-available                                          List all available services"
    echo "    help,-h,--help                                                               Show this help message"
}

ensure_proxifier_dir() {
    if [ ! -d "${PROXIFIER_DIR}" ]; then
        mkdir -p "${PROXIFIER_DIR}"
    fi
}

get_process_file() {
    namespace="$1"
    service="$2"
    echo "${PROXIFIER_DIR}/${namespace}-${service}.pid"
}

forward_port() {
    if [ $# -lt 1 ]; then
        echo "[ERROR] Invalid number of arguments for forward command"
        echo "[TIP] Usage: freeleaps-cluster-proxifier forward <namespace>/<service> -p <local-port>:<service-port>"
        exit 1
    fi

    # Parse namespace/service
    IFS='/' read -r namespace service <<EOF
$1
EOF
    
    if [ -z "${namespace}" ] || [ -z "${service}" ]; then
        echo "[ERROR] Invalid format. Use namespace/service"
        exit 1
    fi

    # Parse port mapping
    if [ "$2" != "-p" ] || [ -z "$3" ]; then
        echo "[ERROR] Invalid port format. Use -p <local-port>:<service-port>"
        exit 1
    fi
    ports="$3"

    # Validate service exists and user has permissions
    if ! kubectl get svc "${service}" -n "${namespace}" >/dev/null 2>&1; then
        if kubectl get namespace "${namespace}" >/dev/null 2>&1; then
            echo "[ERROR] Either the service '${service}' doesn't exist in namespace '${namespace}' or you don't have permission to access it"
            echo "[TIP] Please contact your cluster administrator to request access to this service"
        else
            echo "[ERROR] Namespace '${namespace}' doesn't exist or you don't have permission to access it"
            echo "[TIP] Please contact your cluster administrator to request access to this namespace"
        fi
        exit 1
    fi

    process_file=$(get_process_file "${namespace}" "${service}")
    
    if [ -f "${process_file}" ]; then
        echo "[ERROR] Service ${service} in namespace ${namespace} is already being forwarded"
        echo "[TIP] Use 'freeleaps-cluster-proxifier list' to see active forwards"
        exit 1
    fi

    ensure_proxifier_dir

    echo "[FORWARD] Starting port forward for ${service} in namespace ${namespace}..."
    kubectl port-forward -n "${namespace}" "svc/${service}" "${ports}" > /dev/null 2>&1 & 
    pid=$!

    # Store PID and port mapping
    echo "${pid}:${ports}" > "${process_file}"
    
    echo "[FORWARD] Port forward started successfully"
    echo "[INFO] Service ${service}.${namespace} is now mapping with ${ports}"
}

stop_forward() {
    if [ $# -ne 1 ]; then
        echo "[ERROR] Invalid number of arguments for stop command"
        echo "[TIP] Usage: freeleaps-cluster-proxifier stop <namespace>/<service>"
        exit 1
    fi

    # Parse namespace/service
    IFS='/' read -r namespace service <<EOF
$1
EOF
    
    if [ -z "${namespace}" ] || [ -z "${service}" ]; then
        echo "[ERROR] Invalid format. Use namespace/service"
        exit 1
    fi

    process_file=$(get_process_file "${namespace}" "${service}")

    if [ ! -f "${process_file}" ]; then
        echo "[ERROR] No active forward found for service ${service} in namespace ${namespace}"
        exit 1
    fi

    pid=$(cat "${process_file}" | cut -d: -f1)
    if kill "${pid}" >/dev/null 2>&1; then
        rm "${process_file}"
        echo "[STOP] Stopped forwarding service ${service} in namespace ${namespace}"
    else
        echo "[WARNING] Process not found, cleaning up state file"
        rm "${process_file}"
    fi
}

list_forwards() {
    ensure_proxifier_dir

    echo "Belows are all active port forwards:"
    printf "%-30s %-60s %-15s %-10s\n" "Namespace" "Service" "Port Mapping" "PID"
    
    for file in "${PROXIFIER_DIR}"/*.pid; do
        if [ -f "${file}" ]; then
            name=$(basename "${file}" .pid)
            namespace=$(echo "${name}" | cut -d'-' -f1)
            service=$(echo "${name}" | cut -d'-' -f2-)
            data=$(cat "${file}")
            pid=$(echo "${data}" | cut -d: -f1)
            ports=$(echo "${data}" | cut -d: -f2-)
            
            # Check if process is still running
            if kill -0 "${pid}" >/dev/null 2>&1; then
                printf "%-30s %-60s %-15s %-10s\n" "${namespace}" "${service}" "${ports}" "${pid}"
            else
                echo "[WARNING] Cleaning up stale forward for ${service} in namespace ${namespace}"
                rm "${file}"
            fi
        fi
    done
}

list_available_services() {
    echo "Belows are all available services that you can forward:"
    printf "%-30s %-60s %-10s\n" "Namespace" "Service" "Ports"
    
    # Get all namespaces user has access to
    kubectl get namespaces -o name | cut -d'/' -f2 | while read -r ns; do
        # Get services in each namespace
        if kubectl auth can-i get services -n "${ns}" >/dev/null 2>&1; then
            kubectl get services -n "${ns}" \
                --no-headers \
                -o custom-columns="Namespace:.metadata.namespace,Service:.metadata.name,Ports:.spec.ports[*].port" | \
            while read -r line; do
                # Only show if user has permission to port-forward
                svc_name=$(echo "${line}" | awk '{print $2}')
                if kubectl auth can-i get services/"${svc_name}" -n "${ns}" >/dev/null 2>&1; then
                    namespace=$(echo "${line}" | awk '{print $1}')
                    service=$(echo "${line}" | awk '{print $2}')
                    ports=$(echo "${line}" | awk '{print $3}')
                    printf "%-30s %-60s %-10s\n" "${namespace}" "${service}" "${ports}"
                fi
            done
        fi
    done
}

main() {
    if [ $# -lt 1 ]; then
        echo "[ERROR] No sub-command provided"
        echo "[TIP] Run 'freeleaps-cluster-proxifier -h' to see available sub-commands"
        exit 1
    fi

    subcommand="$1"
    shift

    case "${subcommand}" in
        forward|-f|--forward)
            forward_port "$@"
        ;;
        stop|-s|--stop)
            stop_forward "$@"
        ;;
        list|-l|--list)
            list_forwards
        ;;
        list-available|-la|--list-available)
            list_available_services
        ;;
        help|-h|--help)
            help
        ;;
        *)
            echo "[ERROR] Invalid sub-command: ${subcommand}"
            help
            exit 1
        ;;
    esac
}

main "$@"
