#!/bin/bash

# Bakery IA HTTPS Setup Script
# This script sets up HTTPS with cert-manager and Let's Encrypt for local development

# Remove -e to handle errors more gracefully
set -u

echo "🔒 Setting up HTTPS for Bakery IA with cert-manager and Let's Encrypt"
echo "==============================================================="

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Function to print colored output
print_status() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Check prerequisites
check_prerequisites() {
    print_status "Checking prerequisites..."

    # Check required tools
    local missing_tools=()

    if ! command -v kubectl &> /dev/null; then
        missing_tools+=("kubectl")
    fi

    if ! command -v kind &> /dev/null; then
        missing_tools+=("kind")
    fi

    if ! command -v skaffold &> /dev/null; then
        missing_tools+=("skaffold")
    fi

    if ! command -v colima &> /dev/null; then
        missing_tools+=("colima")
    fi

    # Report missing tools
    if [ ${#missing_tools[@]} -ne 0 ]; then
        print_error "Missing required tools: ${missing_tools[*]}"
        print_error "Please install them with: brew install ${missing_tools[*]}"
        exit 1
    fi

    # Check if Colima is running
    if ! colima status --profile k8s-local &> /dev/null; then
        print_warning "Colima is not running. Starting Colima..."
        colima start --cpu 8 --memory 16 --disk 100 --runtime docker --profile k8s-local
        if [ $? -ne 0 ]; then
            print_error "Failed to start Colima. Please check your Docker installation."
            exit 1
        fi
        print_success "Colima started successfully"
    fi

    # Check if cluster is running or exists
    local cluster_exists=false
    local cluster_running=false

    # Check if Kind cluster exists
    if kind get clusters | grep -q "bakery-ia-local"; then
        cluster_exists=true
        print_status "Kind cluster 'bakery-ia-local' already exists"

        # Check if kubectl can connect to it
        if kubectl cluster-info --context kind-bakery-ia-local &> /dev/null; then
            cluster_running=true
            print_success "Kubernetes cluster is running and accessible"
        else
            print_warning "Kind cluster exists but is not accessible via kubectl"
        fi
    fi

    # Handle cluster creation/recreation
    if [ "$cluster_exists" = true ] && [ "$cluster_running" = false ]; then
        print_warning "Kind cluster exists but is not running. Recreating..."
        kind delete cluster --name bakery-ia-local || true
        cluster_exists=false
    fi

    if [ "$cluster_exists" = false ]; then
        print_warning "Creating new Kind cluster..."
        if [ ! -f "kind-config.yaml" ]; then
            print_error "kind-config.yaml not found. Please ensure you're running this script from the project root."
            exit 1
        fi

        if kind create cluster --config kind-config.yaml; then
            print_success "Kind cluster created successfully"
        else
            print_error "Failed to create Kind cluster. Please check your Kind installation."
            exit 1
        fi
    fi

    # Ensure we're using the correct kubectl context
    kubectl config use-context kind-bakery-ia-local || {
        print_error "Failed to set kubectl context to kind-bakery-ia-local"
        exit 1
    }

    print_success "Prerequisites check passed"
}

# Install cert-manager
install_cert_manager() {
    print_status "Installing cert-manager..."

    # Check if cert-manager is already installed
    if kubectl get namespace cert-manager &> /dev/null; then
        print_warning "cert-manager namespace already exists. Checking if installation is complete..."

        # Check if pods are running
        if kubectl get pods -n cert-manager | grep -q "Running"; then
            print_success "cert-manager is already installed and running"
            return 0
        else
            print_status "cert-manager exists but pods are not ready. Waiting..."
        fi
    else
        # Install cert-manager
        print_status "Installing cert-manager from official release..."
        if kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml; then
            print_success "cert-manager installation started"
        else
            print_error "Failed to install cert-manager. Please check your internet connection and try again."
            exit 1
        fi
    fi

    # Wait for cert-manager namespace to be created
    print_status "Waiting for cert-manager namespace..."
    for i in {1..30}; do
        if kubectl get namespace cert-manager &> /dev/null; then
            break
        fi
        sleep 2
    done

    # Wait for cert-manager pods to be created
    print_status "Waiting for cert-manager pods to be created..."
    for i in {1..60}; do
        if kubectl get pods -n cert-manager &> /dev/null && [ $(kubectl get pods -n cert-manager --no-headers | wc -l) -ge 3 ]; then
            print_success "cert-manager pods created"
            break
        fi
        print_status "Waiting for cert-manager pods... (attempt $i/60)"
        sleep 5
    done

    # Wait for cert-manager pods to be ready
    print_status "Waiting for cert-manager pods to be ready..."

    # Use more reliable selectors for cert-manager components
    local components=(
        "app.kubernetes.io/name=cert-manager"
        "app.kubernetes.io/name=cainjector"
        "app.kubernetes.io/name=webhook"
    )
    local component_names=("cert-manager" "cert-manager-cainjector" "cert-manager-webhook")

    for i in "${!components[@]}"; do
        local selector="${components[$i]}"
        local name="${component_names[$i]}"

        print_status "Waiting for $name to be ready..."

        # First check if pods exist with this selector
        local pod_count=0
        for attempt in {1..30}; do
            pod_count=$(kubectl get pods -n cert-manager -l "$selector" --no-headers 2>/dev/null | wc -l)
            if [ "$pod_count" -gt 0 ]; then
                break
            fi
            sleep 2
        done

        if [ "$pod_count" -eq 0 ]; then
            print_warning "No pods found for $name with selector $selector, trying alternative approach..."
            # Fallback: wait for any pods containing the component name
            if kubectl wait --for=condition=ready pod -n cert-manager --all --timeout=300s 2>/dev/null; then
                print_success "All cert-manager pods are ready"
                break
            else
                print_warning "$name pods not found, but continuing..."
                continue
            fi
        fi

        # Wait for the specific component to be ready
        if kubectl wait --for=condition=ready pod -l "$selector" -n cert-manager --timeout=300s 2>/dev/null; then
            print_success "$name is ready"
        else
            print_warning "$name is taking longer than expected. Checking status..."
            kubectl get pods -n cert-manager -l "$selector" 2>/dev/null || true

            # Continue anyway, sometimes it works despite timeout
            print_warning "Continuing with setup. $name may still be starting..."
        fi
    done

    # Final verification
    if kubectl get pods -n cert-manager | grep -q "Running"; then
        print_success "cert-manager installed successfully"
    else
        print_warning "cert-manager installation may not be complete. Current status:"
        kubectl get pods -n cert-manager
        print_status "Continuing with setup anyway..."
    fi
}

# Install NGINX Ingress Controller
install_nginx_ingress() {
    print_status "Installing NGINX Ingress Controller for Kind..."

    # Check if NGINX Ingress is already installed
    if kubectl get namespace ingress-nginx &> /dev/null; then
        print_warning "NGINX Ingress Controller namespace already exists. Checking status..."

        # Check if controller is running
        if kubectl get pods -n ingress-nginx -l app.kubernetes.io/component=controller | grep -q "Running"; then
            print_success "NGINX Ingress Controller is already running"
        else
            print_status "NGINX Ingress Controller exists but not ready. Waiting..."
            kubectl wait --namespace ingress-nginx \
                --for=condition=ready pod \
                --selector=app.kubernetes.io/component=controller \
                --timeout=300s 2>/dev/null || {
                print_warning "Ingress controller taking longer than expected, but continuing..."
            }
        fi
    else
        # Install NGINX Ingress Controller for Kind (updated URL)
        print_status "Installing NGINX Ingress Controller for Kind..."
        if kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml; then
            print_success "NGINX Ingress Controller installation started"

            # Wait for ingress controller to be ready
            print_status "Waiting for NGINX Ingress Controller to be ready..."
            kubectl wait --namespace ingress-nginx \
                --for=condition=ready pod \
                --selector=app.kubernetes.io/component=controller \
                --timeout=300s 2>/dev/null || {
                print_warning "Ingress controller taking longer than expected, but continuing..."
            }
        else
            print_error "Failed to install NGINX Ingress Controller"
            exit 1
        fi
    fi

    # Configure ingress for permanent localhost access
    print_status "Configuring permanent localhost access..."
    kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec":{"type":"NodePort","ports":[{"name":"http","port":80,"targetPort":"http","nodePort":30080},{"name":"https","port":443,"targetPort":"https","nodePort":30443}]}}' || true

    print_success "NGINX Ingress Controller configured successfully"
}

# Setup cluster issuers
setup_cluster_issuers() {
    print_status "Setting up cluster issuers..."

    # Check if cert-manager components exist
    if [ ! -f "infrastructure/platform/cert-manager/cluster-issuer-staging.yaml" ]; then
        print_error "cert-manager component files not found. Please ensure you're running this script from the project root."
        exit 1
    fi

    # Apply cluster issuers
    print_status "Applying cluster issuers..."

    local issuer_files=(
        "infrastructure/platform/cert-manager/cluster-issuer-staging.yaml"
        "infrastructure/platform/cert-manager/local-ca-issuer.yaml"
        "infrastructure/platform/cert-manager/cluster-issuer-production.yaml"
    )

    for issuer_file in "${issuer_files[@]}"; do
        if [ -f "$issuer_file" ]; then
            print_status "Applying $issuer_file..."
            kubectl apply -f "$issuer_file" || {
                print_warning "Failed to apply $issuer_file, but continuing..."
            }
        else
            print_warning "$issuer_file not found, skipping..."
        fi
    done

    # Wait for the issuers to be created
    print_status "Waiting for cluster issuers to be ready..."
    sleep 15

    # Check if issuers are ready
    print_status "Checking cluster issuer status..."
    kubectl get clusterissuers 2>/dev/null || print_warning "No cluster issuers found yet"

    # Verify that the local CA issuer is ready (if it exists)
    if kubectl get clusterissuer local-ca-issuer &> /dev/null; then
        for i in {1..10}; do
            local issuer_ready=$(kubectl get clusterissuer local-ca-issuer -o jsonpath='{.status.conditions[0].type}' 2>/dev/null || echo "")
            if [[ "$issuer_ready" == "Ready" ]]; then
                print_success "Local CA issuer is ready"
                break
            fi
            print_status "Waiting for local CA issuer to be ready... (attempt $i/10)"
            sleep 10
        done
    else
        print_warning "Local CA issuer not found, skipping readiness check"
    fi

    print_success "Cluster issuers configured successfully"
}

# Deploy the application with HTTPS using Skaffold
deploy_with_https() {
    print_status "Deploying Bakery IA with HTTPS support using Skaffold..."

    # Check if Skaffold is available
    if ! command -v skaffold &> /dev/null; then
        print_error "Skaffold is not installed. Please install skaffold first:"
        print_error "brew install skaffold"
        exit 1
    fi

    # Check if skaffold.yaml exists
    if [ ! -f "skaffold.yaml" ]; then
        print_error "skaffold.yaml not found. Please ensure you're running this script from the project root."
        exit 1
    fi

    # Deploy with Skaffold (builds and deploys automatically with HTTPS support)
    print_status "Building and deploying with Skaffold (dev profile includes HTTPS)..."
    if skaffold run --profile=dev; then
        print_success "Skaffold deployment started"
    else
        print_warning "Skaffold deployment had issues, but continuing..."
    fi

    # Wait for namespace to be created
    print_status "Waiting for bakery-ia namespace..."
    for i in {1..30}; do
        if kubectl get namespace bakery-ia &> /dev/null; then
            print_success "bakery-ia namespace found"
            break
        fi
        sleep 2
    done

    # Check if namespace was created
    if ! kubectl get namespace bakery-ia &> /dev/null; then
        print_warning "bakery-ia namespace not found. Deployment may have failed."
        return 0
    fi

    # Wait for deployments to be ready
    print_status "Waiting for deployments to be ready..."
    if kubectl wait --for=condition=available --timeout=600s deployment --all -n bakery-ia 2>/dev/null; then
        print_success "All deployments are ready"
    else
        print_warning "Some deployments are taking longer than expected, but continuing..."
    fi

    # Verify ingress exists
    if kubectl get ingress bakery-ingress -n bakery-ia &> /dev/null; then
        print_success "HTTPS ingress configured successfully"
    else
        print_warning "Ingress not found, but continuing with setup..."
    fi

    print_success "Application deployed with HTTPS support using Skaffold"
}

# Check certificate status
check_certificates() {
    print_status "Checking certificate status..."

    # Wait for certificate to be issued
    print_status "Waiting for certificates to be issued..."

    # Check if certificate exists
    for i in {1..12}; do
        if kubectl get certificate bakery-ia-tls-cert -n bakery-ia &> /dev/null; then
            print_success "Certificate found"
            break
        fi
        print_status "Waiting for certificate to be created... (attempt $i/12)"
        sleep 10
    done

    # Wait for certificate to be ready
    for i in {1..20}; do
        if kubectl get certificate bakery-ia-tls-cert -n bakery-ia -o jsonpath='{.status.conditions[0].type}' 2>/dev/null | grep -q "Ready"; then
            print_success "Certificate is ready"
            break
        fi
        print_status "Waiting for certificate to be ready... (attempt $i/20)"
        sleep 15
    done

    echo ""
    echo "📋 Certificate status:"
    kubectl get certificates -n bakery-ia 2>/dev/null || print_warning "No certificates found"

    echo ""
    echo "🔍 Certificate details:"
    kubectl describe certificate bakery-ia-tls-cert -n bakery-ia 2>/dev/null || print_warning "Certificate not found"

    echo ""
    echo "🔐 TLS secret status:"
    kubectl get secret bakery-ia-tls-cert -n bakery-ia 2>/dev/null || print_warning "TLS secret not found"
}

# Update hosts file
update_hosts_file() {
    print_status "Checking hosts file configuration..."

    # Get the external IP for Kind
    EXTERNAL_IP="127.0.0.1"

    # Check if entries exist in hosts file
    if ! grep -q "bakery-ia.local" /etc/hosts 2>/dev/null; then
        print_warning "Adding entries to /etc/hosts file for named host access..."

        # Ask for user permission
        read -p "Do you want to add entries to /etc/hosts for named host access? (y/N): " -n 1 -r
        echo
        if [[ $REPLY =~ ^[Yy]$ ]]; then
            # Add hosts entries with proper error handling
            {
                echo "$EXTERNAL_IP bakery-ia.local"
                echo "$EXTERNAL_IP api.bakery-ia.local"
                echo "$EXTERNAL_IP monitoring.bakery-ia.local"
            } | sudo tee -a /etc/hosts > /dev/null

            if [ $? -eq 0 ]; then
                print_success "Hosts file entries added successfully"
            else
                print_error "Failed to update hosts file. You may need to add entries manually."
            fi
        else
            print_warning "Skipping hosts file update. You can still access via https://localhost"
        fi
    else
        print_success "Hosts file entries already exist"
    fi

    echo ""
    print_status "Available access methods:"
    echo "  🌐 Primary: https://localhost (no hosts file needed)"
    echo "  🏷️  Named:   https://bakery-ia.local (requires hosts file)"
    echo "  🔗 API:     https://localhost/api or https://api.bakery-ia.local"
}

# Export CA certificate for browser trust
export_ca_certificate() {
    print_status "Exporting CA certificate for browser trust..."

    # Wait for CA certificate to be created
    for i in {1..10}; do
        if kubectl get secret local-ca-key-pair -n cert-manager &> /dev/null; then
            print_success "CA certificate secret found"
            break
        fi
        print_status "Waiting for CA certificate secret... (attempt $i/10)"
        sleep 10
    done

    # Extract the CA certificate
    if kubectl get secret local-ca-key-pair -n cert-manager &> /dev/null; then
        if kubectl get secret local-ca-key-pair -n cert-manager -o jsonpath='{.data.tls\.crt}' | base64 -d > bakery-ia-ca.crt 2>/dev/null; then
            print_success "CA certificate exported as 'bakery-ia-ca.crt'"

            # Make the certificate file readable
            chmod 644 bakery-ia-ca.crt
        else
            print_warning "Failed to extract CA certificate from secret"
        fi

        print_warning "To trust this certificate and remove browser warnings:"
        echo ""
        echo "📱 macOS:"
        echo "  1. Double-click 'bakery-ia-ca.crt' to open Keychain Access"
        echo "  2. Find 'bakery-ia-local-ca' in the certificates list"
        echo "  3. Double-click it and set to 'Always Trust'"
        echo ""
        echo "🐧 Linux:"
        echo "  sudo cp bakery-ia-ca.crt /usr/local/share/ca-certificates/"
        echo "  sudo update-ca-certificates"
        echo ""
        echo "🪟 Windows:"
        echo "  1. Double-click 'bakery-ia-ca.crt'"
        echo "  2. Click 'Install Certificate'"
        echo "  3. Choose 'Trusted Root Certification Authorities'"
        echo ""
    else
        print_warning "CA certificate secret not found. HTTPS will work but with browser warnings."
        print_warning "You can still access the application at https://localhost"
    fi
}

# Display access information
display_access_info() {
    print_success "🎉 HTTPS setup completed!"
    echo ""
    echo "🌐 Access your application at:"
    echo "  Primary:    https://localhost"
    echo "  API:        https://localhost/api"
    echo "  Named Host: https://bakery-ia.local (if hosts file updated)"
    echo "  API Named:  https://api.bakery-ia.local (if hosts file updated)"
    echo ""
    echo "🛠️  Useful commands:"
    echo "  📋 Check status:        kubectl get all -n bakery-ia"
    echo "  🔍 Check ingress:       kubectl get ingress -n bakery-ia"
    echo "  📜 Check certificates:  kubectl get certificates -n bakery-ia"
    echo "  📝 View service logs:   kubectl logs -f deployment/<service-name> -n bakery-ia"
    echo "  🚀 Development mode:    skaffold dev --profile=dev"
    echo "  🧹 Clean up:           skaffold delete --profile=dev"
    echo "  🔄 Restart service:     kubectl rollout restart deployment/<service-name> -n bakery-ia"
    echo ""
    echo "🔧 Troubleshooting:"
    echo "  🩺 Get events:          kubectl get events -n bakery-ia --sort-by='.firstTimestamp'"
    echo "  🔍 Describe pod:        kubectl describe pod <pod-name> -n bakery-ia"
    echo "  📊 Resource usage:      kubectl top pods -n bakery-ia"
    echo "  🔐 Certificate details: kubectl describe certificate bakery-ia-tls-cert -n bakery-ia"
    echo ""
    if [ -f "bakery-ia-ca.crt" ]; then
        print_warning "📋 Next steps:"
        echo "  1. Import 'bakery-ia-ca.crt' into your browser to remove certificate warnings"
        echo "  2. Access https://localhost to verify the setup"
        echo "  3. Run 'skaffold dev --profile=dev' for development with hot-reload"
    else
        print_warning "⚠️  Note: You may see certificate warnings until the CA certificate is properly configured"
    fi
    echo ""
    print_status "🎯 The application is now ready for secure development!"
}

# Check current cert-manager status for debugging
check_current_cert_manager_status() {
    print_status "Checking current cert-manager status..."

    if kubectl get namespace cert-manager &> /dev/null; then
        echo ""
        echo "📋 Current cert-manager pods status:"
        kubectl get pods -n cert-manager

        echo ""
        echo "🔍 cert-manager deployments:"
        kubectl get deployments -n cert-manager

        # Check for any pending or failed pods
        local failed_pods=$(kubectl get pods -n cert-manager --field-selector=status.phase!=Running --no-headers 2>/dev/null | wc -l)
        if [ "$failed_pods" -gt 0 ]; then
            echo ""
            print_warning "Found $failed_pods non-running pods. Details:"
            kubectl get pods -n cert-manager --field-selector=status.phase!=Running
        fi
        echo ""
    else
        print_status "cert-manager namespace not found. Will install fresh."
    fi
}

# Cleanup function for failed installations
cleanup_on_failure() {
    print_warning "Cleaning up due to failure..."

    # Optional cleanup - ask user
    read -p "Do you want to clean up the Kind cluster and start fresh? (y/N): " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        print_status "Cleaning up Kind cluster..."
        kind delete cluster --name bakery-ia-local || true
        print_success "Cleanup completed. You can run the script again."
    else
        print_status "Keeping existing setup. You can continue manually or run the script again."
    fi
}

# Trap function to handle script interruption
trap 'echo ""; print_warning "Script interrupted. Partial setup may be present."; cleanup_on_failure; exit 1' INT TERM

# Main execution
main() {
    echo "Starting HTTPS setup for Bakery IA..."

    # Set error handling for individual steps
    local step_failed=false

    check_prerequisites || { step_failed=true; }
    if [ "$step_failed" = false ]; then
        check_current_cert_manager_status || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        install_cert_manager || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        install_nginx_ingress || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        setup_cluster_issuers || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        deploy_with_https || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        check_certificates || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        update_hosts_file || { step_failed=true; }
    fi
    if [ "$step_failed" = false ]; then
        export_ca_certificate || { step_failed=true; }
    fi

    if [ "$step_failed" = false ]; then
        display_access_info
        print_success "Setup completed successfully! 🚀"
    else
        print_error "Setup failed at one or more steps. Check the output above for details."
        cleanup_on_failure
        exit 1
    fi
}

# Run main function
main "$@"