#!/bin/bash
# Script pour synchroniser automatiquement tous les secrets TLS depuis les certificats dans OPS
# Usage: ./sync-all-certificates.sh [--sourceCluster "cluster-name"] [--sourceNS "certificates-ops"]

set -e

# Valeurs par défaut
SOURCE_CLUSTER="${SOURCE_CLUSTER:-}"
SOURCE_NS="${SOURCE_NS:-certificates-ops}"

# Parsing des arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --sourceCluster)
            SOURCE_CLUSTER="$2"
            shift 2
            ;;
        --sourceNS)
            SOURCE_NS="$2"
            shift 2
            ;;
        --help|-h)
            echo "Usage: $0 [OPTIONS]"
            echo ""
            echo "Options:"
            echo "  --sourceCluster NAME    Nom du cluster source (défaut: contexte actuel)"
            echo "  --sourceNS NAME         Namespace source (défaut: certificates-ops)"
            echo "  --help, -h              Afficher cette aide"
            echo ""
            echo "Ce script récupère automatiquement tous les certificats depuis OPS"
            echo "et synchronise les secrets TLS vers les clusters appropriés."
            exit 0
            ;;
        *)
            echo "❌ Option inconnue: $1"
            echo "Utilisez --help pour voir l'aide"
            exit 1
            ;;
    esac
done

echo "=== Synchronisation automatique des secrets TLS ==="
echo "Source: $SOURCE_CLUSTER (namespace: $SOURCE_NS)"
echo ""

# Fonction pour déterminer automatiquement les namespaces cibles pour un certificat wildcard
# Détecte automatiquement tous les namespaces qui référencent ce secret dans leurs Ingress/IngressRoute
get_wildcard_target_namespaces() {
    local cert_name=$1
    local secret_name=$2
    local target_cluster=$3
    local env=""
    
    # Extraire l'environnement depuis le nom du certificat
    if [[ $cert_name =~ wildcard-dev-tls ]]; then
        env="dev"
    elif [[ $cert_name =~ wildcard-rct-tls ]]; then
        env="rct"
    elif [[ $cert_name =~ wildcard-prd-tls ]]; then
        env="prd"
    else
        return 1
    fi
    
    echo "   🔍 Détection automatique des namespaces utilisant $secret_name..."
    
    # Initialiser le tableau des namespaces cibles
    WILDCARD_TARGET_NAMESPACES=()
    
    # Récupérer tous les namespaces du cluster cible
    local namespaces
    if [ -z "$target_cluster" ]; then
        namespaces=$(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}' 2>/dev/null)
    else
        namespaces=$(kubectl get namespaces --context="$target_cluster" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null)
    fi
    
    if [ -z "$namespaces" ]; then
        echo "   ⚠️  Aucun namespace trouvé dans le cluster $target_cluster"
        return 1
    fi
    
    # Pour chaque namespace, vérifier s'il contient des Ingress ou IngressRoute qui référencent le secret
    for ns in $namespaces; do
        # Ignorer les namespaces système
        if [[ "$ns" =~ ^(kube-system|kube-public|kube-node-lease|default)$ ]]; then
            continue
        fi
        
        # Vérifier les Ingress (ressource standard Kubernetes)
        local ingress_found=false
        if [ -z "$target_cluster" ]; then
            ingress_found=$(kubectl get ingress -n "$ns" -o json 2>/dev/null | jq -r --arg secret "$secret_name" '.items[] | select(.spec.tls[]?.secretName == $secret) | .metadata.name' 2>/dev/null | head -1)
        else
            ingress_found=$(kubectl get ingress -n "$ns" --context="$target_cluster" -o json 2>/dev/null | jq -r --arg secret "$secret_name" '.items[] | select(.spec.tls[]?.secretName == $secret) | .metadata.name' 2>/dev/null | head -1)
        fi
        
        # Vérifier les IngressRoute (Traefik CRD)
        local ingressroute_found=false
        if [ -z "$target_cluster" ]; then
            ingressroute_found=$(kubectl get ingressroute -n "$ns" -o json 2>/dev/null | jq -r --arg secret "$secret_name" '.items[] | select(.spec.tls.secretName == $secret) | .metadata.name' 2>/dev/null | head -1)
        else
            ingressroute_found=$(kubectl get ingressroute -n "$ns" --context="$target_cluster" -o json 2>/dev/null | jq -r --arg secret "$secret_name" '.items[] | select(.spec.tls.secretName == $secret) | .metadata.name' 2>/dev/null | head -1)
        fi
        
        # Si le secret est référencé dans ce namespace, l'ajouter à la liste
        if [ -n "$ingress_found" ] || [ -n "$ingressroute_found" ]; then
            WILDCARD_TARGET_NAMESPACES+=("$ns")
            echo "      ✅ $ns (détecté via Ingress/IngressRoute)"
        fi
    done
    
    if [ ${#WILDCARD_TARGET_NAMESPACES[@]} -eq 0 ]; then
        echo "   ⚠️  Aucun namespace n'utilise actuellement le secret $secret_name"
        echo "      Le secret sera synchronisé lors de la prochaine utilisation"
        return 0  # Ne pas échouer, juste avertir
    fi
    
    return 0
}

# Fonction pour déterminer le cluster et namespace cible à partir du nom du certificat
# Format attendu: <app>-<env>-tls
# Exemple: homarr-dev-tls -> cluster-dev, namespace homarr-dev
# Pour les certificats wildcard, cette fonction détermine seulement le cluster
determine_target() {
    local cert_name=$1
    
    # Détecter les certificats wildcard
    if [[ $cert_name =~ ^wildcard- ]]; then
        # Pour les certificats wildcard, on détermine seulement le cluster
        # Les namespaces seront déterminés par get_wildcard_target_namespaces
        if [[ $cert_name =~ -dev-tls$ ]]; then
            TARGET_CLUSTER="cluster-dev"
            TARGET_NS=""  # Sera rempli par get_wildcard_target_namespaces
            IS_WILDCARD=true
        elif [[ $cert_name =~ -rct-tls$ ]]; then
            TARGET_CLUSTER="cluster-rct"
            TARGET_NS=""
            IS_WILDCARD=true
        elif [[ $cert_name =~ -prd-tls$ ]]; then
            TARGET_CLUSTER="cluster-prd"
            TARGET_NS=""
            IS_WILDCARD=true
        else
            echo "⚠️  Impossible de déterminer le cluster cible pour $cert_name"
            return 1
        fi
    else
        # Certificats normaux (non-wildcard)
        IS_WILDCARD=false
        # Extraire l'environnement (dev, rct, prd)
        if [[ $cert_name =~ -dev-tls$ ]]; then
            TARGET_CLUSTER="cluster-dev"
            TARGET_NS="${cert_name%-tls}"  # Garde le suffixe -dev
        elif [[ $cert_name =~ -rct-tls$ ]]; then
            TARGET_CLUSTER="cluster-rct"
            TARGET_NS="${cert_name%-tls}"  # Garde le suffixe -rct
        elif [[ $cert_name =~ -prd-tls$ ]]; then
            TARGET_CLUSTER="cluster-prd"
            TARGET_NS="${cert_name%-tls}"  # Garde le suffixe -prd
        else
            # Par défaut, essayer de deviner depuis le nom
            # Si le nom contient "dev", utiliser cluster-dev
            if [[ $cert_name == *"dev"* ]]; then
                TARGET_CLUSTER="cluster-dev"
                TARGET_NS="${cert_name%-tls}"
            else
                echo "⚠️  Impossible de déterminer le cluster cible pour $cert_name"
                return 1
            fi
        fi
    fi
    
    return 0
}

# Déterminer le contexte à utiliser
echo "1. Détermination du contexte kubectl..."
if [ -z "$SOURCE_CLUSTER" ] || [ "$SOURCE_CLUSTER" == "in-cluster" ]; then
    # Utiliser le contexte actuel
    SOURCE_CLUSTER=$(kubectl config current-context 2>/dev/null)
    if [ -z "$SOURCE_CLUSTER" ]; then
        echo "❌ Erreur: Aucun contexte kubectl actuel trouvé"
        echo "   Contextes disponibles:"
        kubectl config get-contexts -o name 2>/dev/null || echo "   (aucun contexte trouvé)"
        exit 1
    fi
    echo "   Utilisation du contexte actuel: $SOURCE_CLUSTER"
else
    # Vérifier que le contexte spécifié existe
    if ! kubectl config get-contexts "$SOURCE_CLUSTER" &>/dev/null; then
        echo "❌ Erreur: Le contexte kubectl '$SOURCE_CLUSTER' n'existe pas"
        echo "   Contextes disponibles:"
        kubectl config get-contexts -o name 2>/dev/null || echo "   (aucun contexte trouvé)"
        exit 1
    fi
    echo "   Utilisation du contexte: $SOURCE_CLUSTER"
fi

# Vérifier l'accès au cluster
echo "2. Vérification de l'accès au cluster..."
if [ -z "$SOURCE_CLUSTER" ]; then
    # Pas de contexte spécifié, utiliser le contexte actuel
    if ! kubectl get nodes &>/dev/null; then
        echo "❌ Erreur: Impossible d'accéder au cluster"
        echo "   Vérifiez votre configuration kubectl et votre connexion réseau"
        exit 1
    fi
else
    # Utiliser le contexte spécifié
    if ! kubectl get nodes --context="$SOURCE_CLUSTER" &>/dev/null; then
        echo "❌ Erreur: Impossible d'accéder au cluster $SOURCE_CLUSTER"
        echo "   Vérifiez votre configuration kubectl et votre connexion réseau"
        exit 1
    fi
fi

# Récupérer tous les certificats
echo "3. Récupération des certificats depuis $SOURCE_CLUSTER..."
if [ -z "$SOURCE_CLUSTER" ]; then
    CERTIFICATES=$(kubectl get certificates -n "$SOURCE_NS" -o json 2>&1)
else
    CERTIFICATES=$(kubectl get certificates -n "$SOURCE_NS" --context="$SOURCE_CLUSTER" -o json 2>&1)
fi
KUBECTL_EXIT_CODE=$?

if [ $KUBECTL_EXIT_CODE -ne 0 ]; then
    echo "❌ Erreur lors de la récupération des certificats:"
    echo "$CERTIFICATES" | head -5
    exit 1
fi

if [ -z "$CERTIFICATES" ] || [ "$CERTIFICATES" == "null" ] || [ "$(echo "$CERTIFICATES" | jq -r '.items // empty')" == "" ]; then
    echo "⚠️  Aucun certificat trouvé dans $SOURCE_NS sur $SOURCE_CLUSTER"
    echo "   Vérifiez que les certificats existent avec:"
            if [ -z "$SOURCE_CLUSTER" ]; then
                echo "   kubectl get certificates -n $SOURCE_NS"
            else
                echo "   kubectl get certificates -n $SOURCE_NS --context=$SOURCE_CLUSTER"
            fi
    exit 0
fi

# Vérifier que jq est installé
if ! command -v jq &> /dev/null; then
    echo "❌ Erreur: jq n'est pas installé"
    echo "   Installez jq avec: sudo apt-get install jq (Ubuntu/Debian) ou brew install jq (macOS)"
    exit 1
fi

# Extraire les certificats et leurs informations
CERT_COUNT=$(echo "$CERTIFICATES" | jq -r '.items | length' 2>/dev/null)
if [ -z "$CERT_COUNT" ] || [ "$CERT_COUNT" == "null" ] || [ "$CERT_COUNT" == "0" ]; then
    echo "⚠️  Aucun certificat trouvé dans $SOURCE_NS sur $SOURCE_CLUSTER"
    exit 0
fi

echo "   Trouvé $CERT_COUNT certificat(s)"
echo ""

# Traiter chaque certificat
SUCCESS_COUNT=0
SKIP_COUNT=0
ERROR_COUNT=0

for i in $(seq 0 $((CERT_COUNT - 1))); do
    CERT_NAME=$(echo "$CERTIFICATES" | jq -r ".items[$i].metadata.name")
    SECRET_NAME=$(echo "$CERTIFICATES" | jq -r ".items[$i].spec.secretName")
    CERT_NAMESPACE=$(echo "$CERTIFICATES" | jq -r ".items[$i].metadata.namespace")
    IS_WILDCARD=false  # Initialisation par défaut
    
    # Si secretName n'est pas défini, utiliser le nom du certificat
    if [ "$SECRET_NAME" == "null" ] || [ -z "$SECRET_NAME" ]; then
        SECRET_NAME="$CERT_NAME"
    fi
    
    echo "📋 Traitement du certificat: $CERT_NAME"
    echo "   Secret: $SECRET_NAME"
    
    # Déterminer le cluster et namespace cible
    if ! determine_target "$CERT_NAME"; then
        echo "   ⚠️  Ignoré (impossible de déterminer la destination)"
        SKIP_COUNT=$((SKIP_COUNT + 1))
        echo ""
        continue
    fi
    
    # Vérifier que le secret existe dans la source
    if [ -z "$SOURCE_CLUSTER" ]; then
        SECRET_CHECK_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\""
    else
        SECRET_CHECK_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\" --context=\"$SOURCE_CLUSTER\""
    fi
    
    if ! eval "$SECRET_CHECK_CMD" &>/dev/null; then
        echo "   ⚠️  Le secret $SECRET_NAME n'existe pas encore (certificat peut-être en cours de génération)"
        SKIP_COUNT=$((SKIP_COUNT + 1))
        echo ""
        continue
    fi
    
    # Récupérer le secret une seule fois
    TEMP_FILE=$(mktemp)
    if [ -z "$SOURCE_CLUSTER" ]; then
        SECRET_GET_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\" -o yaml"
    else
        SECRET_GET_CMD="kubectl get secret \"$SECRET_NAME\" -n \"$SOURCE_NS\" --context=\"$SOURCE_CLUSTER\" -o yaml"
    fi
    
    if ! eval "$SECRET_GET_CMD" > "$TEMP_FILE" 2>/dev/null; then
        echo "   ❌ Erreur: Impossible de récupérer le secret"
        rm -f "$TEMP_FILE"
        ERROR_COUNT=$((ERROR_COUNT + 1))
        echo ""
        continue
    fi
    
    # Traitement spécial pour les certificats wildcard
    if [ "$IS_WILDCARD" = true ]; then
        echo "   🌐 Certificat wildcard détecté"
        
        # Obtenir la liste des namespaces cibles (détection automatique)
        if ! get_wildcard_target_namespaces "$CERT_NAME" "$SECRET_NAME" "$TARGET_CLUSTER"; then
            echo "   ⚠️  Impossible de déterminer les namespaces cibles pour le wildcard"
            rm -f "$TEMP_FILE"
            SKIP_COUNT=$((SKIP_COUNT + 1))
            echo ""
            continue
        fi
        
        if [ ${#WILDCARD_TARGET_NAMESPACES[@]} -eq 0 ]; then
            echo "   ℹ️  Aucun namespace n'utilise actuellement ce certificat"
            rm -f "$TEMP_FILE"
            SKIP_COUNT=$((SKIP_COUNT + 1))
            echo ""
            continue
        fi
        
        echo "   Destination: $TARGET_CLUSTER (namespaces: ${WILDCARD_TARGET_NAMESPACES[*]})"
        
        # Copier le secret dans chaque namespace cible
        for TARGET_NS in "${WILDCARD_TARGET_NAMESPACES[@]}"; do
            echo "   → Synchronisation vers namespace: $TARGET_NS"
            
            # Créer une copie temporaire du fichier pour ce namespace
            TEMP_FILE_NS=$(mktemp)
            cp "$TEMP_FILE" "$TEMP_FILE_NS"
            
            # Modifier les métadonnées pour ce namespace
            sed -i.bak '/^  uid:/d' "$TEMP_FILE_NS" 2>/dev/null || true
            sed -i.bak '/^  resourceVersion:/d' "$TEMP_FILE_NS" 2>/dev/null || true
            sed -i.bak '/^  selfLink:/d' "$TEMP_FILE_NS" 2>/dev/null || true
            sed -i.bak '/^  creationTimestamp:/d' "$TEMP_FILE_NS" 2>/dev/null || true
            sed -i.bak "s/namespace: $SOURCE_NS/namespace: $TARGET_NS/" "$TEMP_FILE_NS" 2>/dev/null || true
            rm -f "${TEMP_FILE_NS}.bak" 2>/dev/null || true
            
            # Créer le namespace s'il n'existe pas
            kubectl create namespace "$TARGET_NS" --context="$TARGET_CLUSTER" --dry-run=client -o yaml | kubectl apply --context="$TARGET_CLUSTER" -f - >/dev/null 2>&1 || true
            
            # Appliquer le secret
            if kubectl apply -f "$TEMP_FILE_NS" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
                # Vérifier que le secret existe maintenant
                if kubectl get secret "$SECRET_NAME" -n "$TARGET_NS" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
                    echo "      ✅ Synchronisé avec succès dans $TARGET_NS"
                    SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
                else
                    echo "      ❌ Erreur: Le secret n'a pas été créé dans $TARGET_NS"
                    ERROR_COUNT=$((ERROR_COUNT + 1))
                fi
            else
                echo "      ❌ Erreur lors de l'application du secret dans $TARGET_NS"
                ERROR_COUNT=$((ERROR_COUNT + 1))
            fi
            
            # Nettoyage
            rm -f "$TEMP_FILE_NS" "${TEMP_FILE_NS}.bak" 2>/dev/null || true
        done
    else
        # Certificats normaux (non-wildcard) - comportement original
        echo "   Destination: $TARGET_CLUSTER (namespace: $TARGET_NS)"
        echo "   Synchronisation en cours..."
        
        # Modifier les métadonnées
        sed -i.bak '/^  uid:/d' "$TEMP_FILE" 2>/dev/null || true
        sed -i.bak '/^  resourceVersion:/d' "$TEMP_FILE" 2>/dev/null || true
        sed -i.bak '/^  selfLink:/d' "$TEMP_FILE" 2>/dev/null || true
        sed -i.bak '/^  creationTimestamp:/d' "$TEMP_FILE" 2>/dev/null || true
        sed -i.bak "s/namespace: $SOURCE_NS/namespace: $TARGET_NS/" "$TEMP_FILE" 2>/dev/null || true
        rm -f "${TEMP_FILE}.bak" 2>/dev/null || true
        
        # Créer le namespace s'il n'existe pas
        kubectl create namespace "$TARGET_NS" --context="$TARGET_CLUSTER" --dry-run=client -o yaml | kubectl apply --context="$TARGET_CLUSTER" -f - >/dev/null 2>&1 || true
        
        # Appliquer le secret
        if kubectl apply -f "$TEMP_FILE" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
            # Vérifier que le secret existe maintenant
            if kubectl get secret "$SECRET_NAME" -n "$TARGET_NS" --context="$TARGET_CLUSTER" >/dev/null 2>&1; then
                echo "   ✅ Synchronisé avec succès"
                SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
            else
                echo "   ❌ Erreur: Le secret n'a pas été créé"
                ERROR_COUNT=$((ERROR_COUNT + 1))
            fi
        else
            echo "   ❌ Erreur lors de l'application du secret"
            ERROR_COUNT=$((ERROR_COUNT + 1))
        fi
    fi
    
    # Nettoyage
    rm -f "$TEMP_FILE" "${TEMP_FILE}.bak" 2>/dev/null || true
    
    echo ""
done

# Résumé
echo "=== Résumé ===" 
echo "✅ Synchronisés avec succès: $SUCCESS_COUNT"
echo "⚠️  Ignorés: $SKIP_COUNT"
echo "❌ Erreurs: $ERROR_COUNT"
echo ""

if [ $ERROR_COUNT -eq 0 ] && [ $SUCCESS_COUNT -gt 0 ]; then
    echo "🎉 Toutes les synchronisations réussies !"
    exit 0
elif [ $ERROR_COUNT -gt 0 ]; then
    echo "⚠️  Certaines synchronisations ont échoué"
    exit 1
else
    echo "ℹ️  Aucune synchronisation effectuée"
    exit 0
fi

 