#!/bin/bash
set -e

# Retry helm s3 push with backoff to handle S3 PreconditionFailed 412 race conditions
helm_s3_push_with_retry() {
    local chart_file="$1"
    local repo_name="$2"
    local max_retries=5
    local attempt=1
    local wait_time=5
    while [ $attempt -le $max_retries ]; do
        if helm s3 push "${chart_file}" "${repo_name}" --force 2>&1; then
            return 0
        fi
        echo "helm s3 push failed (attempt ${attempt}/${max_retries}), retrying in ${wait_time}s..."
        sleep $wait_time
        wait_time=$((wait_time * 2))
        attempt=$((attempt + 1))
    done
    echo "ERROR: helm s3 push failed after ${max_retries} attempts"
    return 1
}

# Retry git push with rebase to handle concurrent pipeline race conditions
git_push_with_retry() {
    local branch="${1:-master}"
    local max_retries=5
    local attempt=1
    while [ $attempt -le $max_retries ]; do
        if git push origin "$branch" 2>&1; then
            return 0
        fi
        echo "Push failed (attempt ${attempt}/${max_retries}), rebasing and retrying..."
        git pull --rebase origin "$branch"
        attempt=$((attempt + 1))
    done
    echo "ERROR: Failed to push after ${max_retries} attempts"
    return 1
}
echo "=== Starting deployment of Package Travelbrands Service to PRODUCTION ==="

# Configuration
SERVICE_NAME="tbi-package-travelbrands"
NAMESPACE="access"
ENVIRONMENT="${DEPLOY_ENV:-dev}"
AWS_REGION="${AWS_REGION:-ca-central-1}"
TBI_ENVIRONMENTS_BRANCH="${TBI_ENVIRONMENTS_BRANCH:-master}"
HELM_REPO_URL="${HELM_REPO_URL:-https://tbi-charts-prod.s3.amazonaws.com}"
HELM_S3_BUCKET="${HELM_S3_BUCKET:-tbi-charts-prod}"

# ========================================
# PRODUCTION SAFETY CHECKS
# ========================================

echo ""
echo "🔒 ========================================="
echo "🔒 PRODUCTION DEPLOYMENT SAFETY CHECKS"
echo "🔒 ========================================="

# Check 1: Verify DEPLOY_ENV is set to prod
if [ -z "${DEPLOY_ENV}" ]; then
    echo "❌ ERROR: DEPLOY_ENV environment variable is not set!"
    echo "Expected: prod"
    echo "This should be set in CircleCI context 'devops-mgt-prod'"
    exit 1
fi

if [ "${DEPLOY_ENV}" != "prod" ]; then
    echo "❌ ERROR: DEPLOY_ENV is not 'prod'!"
    echo "Expected: prod"
    echo "Got: ${DEPLOY_ENV}"
    echo "Production deployments MUST have DEPLOY_ENV=prod"
    exit 1
fi

echo "✅ DEPLOY_ENV verified: ${DEPLOY_ENV}"

# Validate required environment variables
if [ -z "${CLUSTER_NAME}" ]; then
    echo "❌ ERROR: CLUSTER_NAME environment variable is not set!"
    echo "This should be set in CircleCI context (expected: 'tbi-prod')"
    exit 1
fi

# Check 2: Verify cluster name is production
if [[ ! "${CLUSTER_NAME}" =~ prod ]]; then
    echo "❌ ERROR: CLUSTER_NAME does not contain 'prod'!"
    echo "Expected: tbi-prod"
    echo "Got: ${CLUSTER_NAME}"
    echo "Refusing to deploy to non-production cluster in production pipeline!"
    exit 1
fi

echo "✅ Cluster verified: ${CLUSTER_NAME}"

if [ -z "${AWS_ACCOUNT_ID}" ]; then
    echo "❌ ERROR: AWS_ACCOUNT_ID environment variable is not set!"
    echo "This is required to construct ECR image URLs"
    exit 1
fi

# GitHub authentication - uses GITHUB_TOKEN for HTTPS access
if [ -z "${GITHUB_TOKEN}" ]; then
    echo "❌ ERROR: GITHUB_TOKEN environment variable is not set!"
    echo "This token is required to clone and push to tbi-environments repository"
    exit 1
fi
TBI_ENVIRONMENTS_REPO="https://github.com/redlabelvacations/tbi-environments.git"

# Read image tag from workspace (created by build job)
if [ -f "IMAGE_TAG" ]; then
    CHART_VERSION=$(cat IMAGE_TAG | tr -d '[:space:]')
    echo "Using image tag from build job: ${CHART_VERSION}"
else
    echo "⚠️  WARNING: IMAGE_TAG file not found, calculating from VERSION file"
    if [ ! -f "VERSION" ]; then
        echo "❌ ERROR: VERSION file not found!"
        exit 1
    fi
    BASE_VERSION=$(cat VERSION | tr -d '[:space:]')
    CHART_VERSION="${BASE_VERSION}-${CIRCLE_BRANCH}-${CIRCLE_BUILD_NUM}"
fi

# Check 3: Validate production image tag
echo ""
echo "Validating PRODUCTION image tag: ${CHART_VERSION}"

# Reject dev/qa/uat tags
if [[ "${CHART_VERSION}" =~ (develop|qa|uat) ]]; then
    echo "❌ ERROR: Cannot deploy dev/qa/uat image tags to production!"
    echo "Image tag: ${CHART_VERSION}"
    echo "Production requires stable release tags only"
    exit 1
fi

# Reject 'latest' tag
if [[ "${CHART_VERSION}" == "latest" ]]; then
    echo "❌ ERROR: 'latest' tag not allowed in production!"
    echo "Production requires explicit version tags"
    exit 1
fi

# Validate production tag format
# Accepts: X.Y.Z (clean semver) or X.Y.Z-master-BUILD (legacy)
if [[ "${CHART_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    echo "✅ Production clean version tag: ${CHART_VERSION}"
elif [[ "${CHART_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-master-[0-9]+$ ]]; then
    echo "✅ Production legacy version tag: ${CHART_VERSION}"
else
    echo "⚠️  WARNING: Image tag doesn't match expected production patterns"
    echo "Expected: X.Y.Z or X.Y.Z-master-BUILD"
    echo "Got: ${CHART_VERSION}"
    echo "Continuing anyway... (manual builds may have different patterns)"
fi

echo "✅ Image tag validated for production: ${CHART_VERSION}"

# ========================================
# END PRODUCTION SAFETY CHECKS
# ========================================

echo ""
echo "🔒 Production Deployment Configuration:"
echo "   Chart Version: ${CHART_VERSION}"
echo "   Environment: ${ENVIRONMENT}"
echo "   Namespace: ${NAMESPACE}"
echo "   Cluster: ${CLUSTER_NAME}"
echo "   Service: ${SERVICE_NAME}"
echo "   AWS Region: ${AWS_REGION}"
echo ""

# Function to package Helm chart
package_helm_chart() {
    echo ""
    echo "=== Packaging Helm chart for ${SERVICE_NAME} (PRODUCTION) ==="

    local chart_path="tbi-devops-environments/${ENVIRONMENT}/tbi-package-travelbrands/charts/${SERVICE_NAME}"

    if [ ! -d "${chart_path}" ]; then
        echo "❌ ERROR: Chart directory not found: ${chart_path}"
        return 1
    fi

    # Update Chart.yaml with new version
    echo "Updating chart version to ${CHART_VERSION}..."
    sed -i.bak "s|version:.*|version: ${CHART_VERSION}|g" ${chart_path}/Chart.yaml
    sed -i.bak "s|appVersion:.*|appVersion: \"${CHART_VERSION}\"|g" ${chart_path}/Chart.yaml
    rm -f ${chart_path}/Chart.yaml.bak

    # Package the chart
    echo "Packaging chart..."
    mkdir -p /tmp/helm-charts
    helm package ${chart_path} -d /tmp/helm-charts

    echo "✅ ${SERVICE_NAME} chart packaged"
}

# Function to push chart to S3 Helm repository using helm-s3 plugin
push_chart_to_s3_repo() {
    local chart_file="/tmp/helm-charts/${SERVICE_NAME}-${CHART_VERSION}.tgz"

    echo ""
    echo "=== Pushing ${SERVICE_NAME} chart to S3 Helm repository (PRODUCTION) ==="

    if [ ! -f "${chart_file}" ]; then
        echo "❌ ERROR: Chart file not found: ${chart_file}"
        return 1
    fi

    # Use helm-s3 plugin to push chart (automatically updates index.yaml)
    helm_s3_push_with_retry ${chart_file} tbi-charts

    echo "✅ ${SERVICE_NAME} chart pushed to S3 repository"
}

# Function to clone tbi-environments repo
clone_tbi_environments() {
    echo ""
    echo "=== Cloning tbi-environments repository (PRODUCTION) ==="

    if [ -d "/tmp/tbi-environments" ]; then
        rm -rf /tmp/tbi-environments
    fi

    # Authenticate via a credential helper (survives GitHub's redirect, unlike an
    # inline token in the URL), and persist it on the clone so the later push works.
    git -c credential.helper= \
        -c credential.helper='!f() { echo "username=x-access-token"; echo "password=${GITHUB_TOKEN}"; }; f' \
        clone "${TBI_ENVIRONMENTS_REPO}" /tmp/tbi-environments
    git -C /tmp/tbi-environments config credential.helper '!f() { echo "username=x-access-token"; echo "password=${GITHUB_TOKEN}"; }; f'
    cd /tmp/tbi-environments
    git checkout ${TBI_ENVIRONMENTS_BRANCH}

    echo "✅ tbi-environments cloned successfully"
}

# Function to update requirements.yaml
update_requirements() {
    echo ""
    echo "=== Updating requirements.yaml for ${SERVICE_NAME} (PRODUCTION) ==="

    local req_file="/tmp/tbi-environments/${ENVIRONMENT}/requirements.yaml"

    if [ ! -f "${req_file}" ]; then
        echo "❌ ERROR: Requirements file not found: ${req_file}"
        return 1
    fi

    # Update version using sed (simple approach)
    # This looks for the service name and updates the version on the next line
    sed -i.bak "/name: ${SERVICE_NAME}/,/version:/ s|version:.*|version: ${CHART_VERSION}|" ${req_file}
    rm -f ${req_file}.bak

    echo "✅ Updated ${SERVICE_NAME} to version ${CHART_VERSION} in requirements.yaml"
}

# Function to update image in values file
update_values_file() {
    echo ""
    echo "=== Updating values file for ${SERVICE_NAME} (PRODUCTION) ==="

    local values_file="/tmp/tbi-environments/${ENVIRONMENT}/values/${SERVICE_NAME}.yaml"

    if [ ! -f "${values_file}" ]; then
        echo "❌ ERROR: Values file not found: ${values_file}"
        return 1
    fi

    # Construct ECR image URL
    local image_url="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${SERVICE_NAME}:${CHART_VERSION}"

    echo "Production image URL: ${image_url}"

    # Check if image field exists in the file
    if grep -q "^image:" "${values_file}"; then
        # Update existing image field
        sed -i.bak "s|^image:.*|image: ${image_url}|" ${values_file}
        echo "Updated existing image field"
    else
        # Add image field at the top of the file (after any initial comments)
        sed -i.bak "1 a\\
image: ${image_url}" ${values_file}
        echo "Added new image field"
    fi
    rm -f ${values_file}.bak

    echo "✅ Updated ${SERVICE_NAME} image to ${image_url}"
}

# Function to commit and push values file changes
push_values_update() {
    echo ""
    echo "=== Pushing values file updates (PRODUCTION) ==="

    cd /tmp/tbi-environments

    # Configure git
    git config user.name "CircleCI Bot"
    git config user.email "circleci@tbidevelopment.ca"

    # Show changes
    echo "Changes made:"
    git diff ${ENVIRONMENT}/values/
    git diff ${ENVIRONMENT}/requirements.yaml

    # Stage files for commit
    git add ${ENVIRONMENT}/values/${SERVICE_NAME}.yaml
    git add ${ENVIRONMENT}/requirements.yaml

    # Check if there are any changes to commit
    if git diff --cached --quiet; then
        echo "ℹ️  No changes detected - values already up to date with version ${CHART_VERSION}"
        echo "Skipping commit and continuing with deployment..."
    else
        # Commit and push values file AND requirements.yaml
        git commit -m "🔒 PRODUCTION: Update Package Travelbrands to ${CHART_VERSION}

Deployed by CircleCI build #${CIRCLE_BUILD_NUM}
Branch: ${CIRCLE_BRANCH}
Service: ${SERVICE_NAME}
Environment: PRODUCTION

Changes:
- Updated values file with ECR image URL: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${SERVICE_NAME}:${CHART_VERSION}
- Updated requirements.yaml with chart version: ${CHART_VERSION}
"
        git_push_with_retry "${TBI_ENVIRONMENTS_BRANCH}"
        echo "✅ Values file and requirements.yaml updated and pushed"
    fi
}

# Function to deploy service using helm secrets
deploy_service() {
    echo ""
    echo "=== Deploying ${SERVICE_NAME} using helm secrets (PRODUCTION) ==="

    cd /tmp/tbi-environments

    # Display expected image (should match what's in values file)
    local image_url="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${SERVICE_NAME}:${CHART_VERSION}"
    echo "🔒 PRODUCTION deployment image: ${image_url}"

    # Deploy using helm secrets
    # NOTE: Image is read from values/${SERVICE_NAME}.yaml, NOT from --set parameter
    # This ensures ArgoCD-compatible configuration and uses Git-tracked values

    # Configure for cross-account KMS access
    # Production credentials (account 489176460030) access KMS key in account 495680544243
    # KMS key policy must allow cross-account access from production account
    echo "Configuring production credentials for kubectl and SOPS (cross-account KMS)..."

    # Ensure CircleCI context credentials are used (not EC2 instance role)
    if [ -z "${AWS_ACCESS_KEY_ID}" ] || [ -z "${AWS_SECRET_ACCESS_KEY}" ]; then
        echo "❌ ERROR: AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY not set!"
        echo "These must be set in CircleCI context 'devops-mgt-prod'"
        exit 1
    fi

    # Write credentials to file to ensure they take precedence over instance role
    mkdir -p ~/.aws
    cat > ~/.aws/credentials << EOF
[default]
aws_access_key_id = ${AWS_ACCESS_KEY_ID}
aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}
EOF

    cat > ~/.aws/config << EOF
[default]
region = ${AWS_REGION}
EOF

    # Create .sops.yaml with KMS key (no aws_profile - uses default credentials)
    cat > /tmp/tbi-environments/.sops.yaml << 'SOPSEOF'
creation_rules:
  - kms: arn:aws:kms:ca-central-1:495680544243:key/99547b03-9580-403f-8579-ea1595335830
SOPSEOF

    # Verify production credentials are being used (not instance role)
    echo "Verifying production AWS credentials..."
    PROD_IDENTITY=$(aws sts get-caller-identity --output json)
    PROD_ACCOUNT=$(echo "$PROD_IDENTITY" | jq -r '.Account')
    PROD_ARN=$(echo "$PROD_IDENTITY" | jq -r '.Arn')

    echo "Production identity: $PROD_ARN"
    echo "Production account: $PROD_ACCOUNT"

    # Ensure we're not using an EC2 instance role
    if [[ "$PROD_ARN" == *":assumed-role/"*"/i-"* ]]; then
        echo "❌ ERROR: Using EC2 instance role instead of CircleCI credentials!"
        echo "   Current identity: $PROD_ARN"
        echo "   This indicates AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY are not being used"
        exit 1
    fi

    if [ "$PROD_ACCOUNT" != "489176460030" ]; then
        echo "❌ ERROR: Not using production account credentials!"
        echo "   Expected account: 489176460030"
        echo "   Current account: $PROD_ACCOUNT"
        exit 1
    fi

    echo "✅ Using production credentials for both kubectl and SOPS"
    echo "✅ SOPS will use cross-account KMS access to decrypt secrets"
    echo "   Production account: 489176460030"
    echo "   KMS key account: 495680544243"
    echo "   KMS key policy must allow this production IAM principal: $PROD_ARN"

    echo "Running: helm secrets upgrade --install --namespace ${NAMESPACE} ${SERVICE_NAME} --set cluster=${CLUSTER_NAME} --version ${CHART_VERSION}"

    # Deploy using helm secrets with production credentials
    # SOPS will use the same credentials for cross-account KMS access
    helm secrets upgrade --install \
        --namespace ${NAMESPACE} ${SERVICE_NAME} \
        tbi-charts/${SERVICE_NAME} \
        --set cluster="${CLUSTER_NAME}" \
        --version ${CHART_VERSION} \
        --reset-values \
        -f ./${ENVIRONMENT}/common.yaml \
        -f ./${ENVIRONMENT}/secrets.common.yaml \
        -f ./${ENVIRONMENT}/values/${SERVICE_NAME}.yaml \
        -f ./${ENVIRONMENT}/secrets/secrets.${SERVICE_NAME}.yaml
    
    # Return to original directory
    cd "${ORIGINAL_DIR}"

    # Verify deployment
    echo "Verifying PRODUCTION deployment..."
    kubectl rollout status deployment/${SERVICE_NAME} -n ${NAMESPACE} --timeout=5m

    echo "✅ ${SERVICE_NAME} deployed successfully to PRODUCTION"
}

# ========================================
# MAIN DEPLOYMENT FLOW
# ========================================

echo ""
echo "=== Step 1: Package Helm chart ==="
package_helm_chart

echo ""
echo "=== Step 2: Initialize Helm S3 repository ==="
helm repo add tbi-charts s3://${HELM_S3_BUCKET}/

echo ""
echo "=== Step 3: Push chart to S3 repository ==="
push_chart_to_s3_repo

echo ""
echo "=== Step 4: Clone tbi-environments repository ==="
clone_tbi_environments

echo ""
echo "=== Step 5: Update values file with image URL ==="
update_values_file

echo ""
echo "=== Step 6: Update requirements.yaml ==="
update_requirements

echo ""
echo "=== Step 7: Commit and push values file update ==="
push_values_update

echo ""
echo "=== Step 8: Update Helm repository ==="
helm repo update

echo ""
echo "=== Step 9: Deploy service to Kubernetes ==="
deploy_service

echo ""
echo "=== Deployment Summary (PRODUCTION) ==="
kubectl get deployments -n ${NAMESPACE}
kubectl get pods -n ${NAMESPACE}

echo ""
echo "=== 🔒 PRODUCTION DEPLOYMENT COMPLETE ==="
echo "Service deployed to version: ${CHART_VERSION}"
echo "Environment: PRODUCTION"
echo "Cluster: ${CLUSTER_NAME}"
echo "Namespace: ${NAMESPACE}"
