#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

ROOT=$(cd $(dirname "${BASH_SOURCE[0]}")/../..; pwd -P)

WITH_KUBECONFIG=true
source $ROOT/hack/lib/vars.sh
source $ROOT/hack/lib/image.sh

# tools
KUBECTL=${KUBECTL:-"kubectl"}
GINKGO=${GINKGO:-"$ROOT/bin/ginkgo"}

FREE_TIER_KUBECONFIG=${VAR_KUBECONFIG:-"$KUBECONFIG"}
FREE_TIER_CONTEXT=${VAR_CONTEXT:-"arn:aws:eks:us-east-1:385595570414:cluster/dev-us-east-1-f01"}
INFRA_CLUSTER_TABLE="serverless_cluster_dev"

RANDOM_CLUSTER=${RANDOM_CLUSTER:-"$(git config user.name)"}
MANAGER_NS=e2etesting-system-$RANDOM_CLUSTER
TIDB_POOL_NS=e2etesting-system-$RANDOM_CLUSTER-tidb-pool
VIP_TIDB_POOL_NS=e2etesting-system-$RANDOM_CLUSTER-vip-tidb-pool
FOCUS=${FOCUS:-".*"}
CLEANUP=${CLEANUP:-0}
SKIP_DEPLOY=${SKIP_DEPLOY:-0}
SELECTOR=${SELECTOR:-"For=Core"}
# Definition for MySQL operations
MYSQL_DB_HOST="127.0.0.1"
MYSQL_DB_PORT=""
MYSQL_DB_USER=""
MYSQL_DB_PASSWORD=""
MYSQL_DB_NAME=""
# Event types and statuses for cluster_events table (assuming common values)
EVENT_TYPE_CLUSTER_UPDATED="UPDATED"
STATUS_PENDING="PENDING"
COMPONENT_NAME="e2e-test-cleanup"
# manual or auto
MODE=${MODE:-"manual"}
TEST_ENV="mock-eks"
GINKGO_POLL_PROGRESS_AFTER=${GINKGO_POLL_PROGRESS_AFTER:-"10m"}
GINKGO_POLL_PROGRESS_INTERVAL=${GINKGO_POLL_PROGRESS_INTERVAL:-"1m"}
RDS_TUNNEL_POD=${RDS_TUNNEL_POD:-"rds-tunnel"}
RDS_TUNNEL_IMAGE=${RDS_TUNNEL_IMAGE:-"gcr.io/pingcap-public/third-party/socat"}
RDS_TUNNEL_LOG=${RDS_TUNNEL_LOG:-"/tmp/rds-port-forward.log"}
RDS_TUNNEL_PID=""
RDS_SECRET_ID=${RDS_SECRET_ID:-"dev-${VAR_AWS_REGION}-serverless-infra-rds-secret"}

execute_sql() {
    local sql_query="$1"
    MYSQL_PWD="${MYSQL_DB_PASSWORD}" mysql -h"${MYSQL_DB_HOST}" -P"${MYSQL_DB_PORT}" -u"${MYSQL_DB_USER}" --database="${MYSQL_DB_NAME}" -s -N -e "${sql_query}"
}

e2e:deleteItems() {
    local KUBERNETES_TAG="$1"

    echo "Connecting to MySQL: ${MYSQL_DB_USER}@${MYSQL_DB_HOST}:${MYSQL_DB_PORT}/${MYSQL_DB_NAME}"
    echo "Fetching cluster IDs for kubernetes tag '${KUBERNETES_TAG}'..."
    CLUSTER_IDS=$(execute_sql "SELECT cluster_id FROM clusters WHERE kubernetes = '${KUBERNETES_TAG}' AND deletion_timestamp IS NULL;")

    if [ -z "$CLUSTER_IDS" ]; then
        echo "No active clusters found for kubernetes tag '${KUBERNETES_TAG}'. Exiting soft-delete."
        return 0
    fi

    echo "Found clusters to soft-delete: ${CLUSTER_IDS}"
    for CLUSTER_ID in ${CLUSTER_IDS}; do
        echo "Processing cluster_id: ${CLUSTER_ID} "

        SOFT_DELETE_SQL="SET @cluster_id = '${CLUSTER_ID}';
SET @kubernetes_tag = '${KUBERNETES_TAG}';
SET @component_name = '${COMPONENT_NAME}';
SET @event_type = '${EVENT_TYPE_CLUSTER_UPDATED}';
SET @status = '${STATUS_PENDING}';

START TRANSACTION;

UPDATE clusters SET deletion_timestamp = NOW(6) WHERE cluster_id = @cluster_id COLLATE utf8mb4_general_ci AND deletion_timestamp IS NULL;
SET @new_version = (SELECT resource_version FROM cluster_statuses WHERE cluster_id = @cluster_id COLLATE utf8mb4_general_ci) + 1;
UPDATE cluster_statuses SET resource_version = @new_version WHERE cluster_id = @cluster_id COLLATE utf8mb4_general_ci;
INSERT INTO cluster_events (namespace, name, kubernetes, event_type, status, source_component, resource_version, created_at, updated_at) 
    SELECT namespace, @cluster_id, @kubernetes_tag, @event_type, @status, @component_name, @new_version, NOW(6), NOW(6) 
    FROM clusters WHERE cluster_id = @cluster_id COLLATE utf8mb4_general_ci;

COMMIT;"

        if ! execute_sql "${SOFT_DELETE_SQL}"; then
            echo "Error soft-deleting cluster ${CLUSTER_ID}. Continuing with next..."
        fi
    done
}

e2e:waitItems() {
    local KUBERNETES_TAG="$1"
    local TIMEOUT="$2"
    local INTERVAL=10 # seconds
    local ELAPSED=0

    while [ $ELAPSED -lt $TIMEOUT ]; do
        COUNT=$(execute_sql "SELECT COUNT(*) FROM clusters WHERE kubernetes = '${KUBERNETES_TAG}';")

        if [[ -z "$COUNT" || "$COUNT" -eq 0 ]]; then
            echo "All items with kubernetes tag '${KUBERNETES_TAG}' have been deleted in MySQL."
            execute_sql "DELETE FROM cluster_events WHERE kubernetes = '${KUBERNETES_TAG}';"
            echo "Cleaned up cluster_events for kubernetes tag '${KUBERNETES_TAG}'."
            return 0
        fi

        echo "Found $COUNT items not yet deleted for kubernetes tag '${KUBERNETES_TAG}'. Waiting..."
        sleep $INTERVAL
        ELAPSED=$((ELAPSED + INTERVAL))
    done

    echo "Error: Timeout reached. Some items with kubernetes tag '${KUBERNETES_TAG}' were deleted in MySQL."
    return 1
}

e2e::load_aws_rds_credentials() {
    echo "Fetching RDS credentials from AWS Secrets Manager: ${RDS_SECRET_ID}"
    secret_string=$(aws secretsmanager get-secret-value \
        --secret-id "${RDS_SECRET_ID}" \
        --query SecretString \
        --output text \
        --region "${VAR_AWS_REGION}")

    if [ -z "${secret_string}" ]; then
        echo "Failed to retrieve non-empty RDS secret string from Secrets Manager."
        return 1
    fi

    RDS_HOST=$(echo "${secret_string}" | jq -er '.host') # no need export
    RDS_PORT=$(echo "${secret_string}" | jq -er '.port'); export RDS_PORT
    RDS_USERNAME=$(echo "${secret_string}" | jq -er '.username'); export RDS_USERNAME
    RDS_PASSWORD=$(echo "${secret_string}" | jq -er '.password'); export RDS_PASSWORD
    RDS_DBNAME=$(echo "${secret_string}" | jq -er '.dbname'); export RDS_DBNAME
}

e2e::start_rds_tunnel() {
    $KUBECTL delete pod "${RDS_TUNNEL_POD}" \
        -n "${MANAGER_NS}" \
        --ignore-not-found=true \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT}

    $KUBECTL run "${RDS_TUNNEL_POD}" \
        -n "${MANAGER_NS}" \
        --image="${RDS_TUNNEL_IMAGE}" \
        --restart=Never \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT} \
        --command -- \
        sh -c "exec socat TCP-LISTEN:${RDS_PORT},fork,reuseaddr TCP:${RDS_HOST}:${RDS_PORT}"

    if ! $KUBECTL wait --for=condition=Ready "pod/${RDS_TUNNEL_POD}" \
        -n "${MANAGER_NS}" \
        --timeout=120s \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT}; then
        echo "Tunnel pod failed to become Ready."
        $KUBECTL get pod "${RDS_TUNNEL_POD}" \
            -n "${MANAGER_NS}" \
            -o wide \
            --kubeconfig=${FREE_TIER_KUBECONFIG} \
            --context=${FREE_TIER_CONTEXT} || true
        $KUBECTL describe pod "${RDS_TUNNEL_POD}" \
            -n "${MANAGER_NS}" \
            --kubeconfig=${FREE_TIER_KUBECONFIG} \
            --context=${FREE_TIER_CONTEXT} || true
        $KUBECTL logs "${RDS_TUNNEL_POD}" \
            -n "${MANAGER_NS}" \
            --kubeconfig=${FREE_TIER_KUBECONFIG} \
            --context=${FREE_TIER_CONTEXT} || true
        $KUBECTL get events \
            -n "${MANAGER_NS}" \
            --sort-by=.metadata.creationTimestamp \
            --kubeconfig=${FREE_TIER_KUBECONFIG} \
            --context=${FREE_TIER_CONTEXT} | tail -n 80 || true
        return 1
    fi

    $KUBECTL port-forward \
        --address 127.0.0.1 \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT} \
        -n "${MANAGER_NS}" \
        "pod/${RDS_TUNNEL_POD}" \
        "${RDS_PORT}:${RDS_PORT}" >"${RDS_TUNNEL_LOG}" 2>&1 &
    RDS_TUNNEL_PID=$!

    echo "Waiting 5 seconds for tunnel to be established..."
    sleep 5

    if ! kill -0 "${RDS_TUNNEL_PID}" 2>/dev/null; then
        cat "${RDS_TUNNEL_LOG}" || true
        echo "Failed to start kubectl port-forward."
        return 1
    fi
}

e2e::stop_rds_tunnel() {
    if [[ -n "${RDS_TUNNEL_PID}" ]]; then
        echo "Terminating kubectl port-forward process (PID: ${RDS_TUNNEL_PID})..."
        kill "${RDS_TUNNEL_PID}" || true
    fi

    echo "Deleting tunnel pod ${RDS_TUNNEL_POD}"
    $KUBECTL delete pod "${RDS_TUNNEL_POD}" \
        -n "${MANAGER_NS}" \
        --ignore-not-found=true \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT} || true
}

e2e::cleanup() {
    e2e:deleteItems ${RANDOM_CLUSTER}
    e2e:waitItems ${RANDOM_CLUSTER} 300

    $KUBECTL wait --for delete ns \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT} \
        --timeout=15m \
        -l testing.tidbcloud.com/for=e2e,testing.tidbcloud.com/e2e-id="${RANDOM_CLUSTER}"

    $ROOT/hack/pulumi/deploy.sh uninstall_tidb_worker $TEST_ENV "$RANDOM_CLUSTER"
    $ROOT/hack/pulumi/deploy.sh uninstall_gateway $TEST_ENV "$RANDOM_CLUSTER"
    $ROOT/hack/pulumi/deploy.sh uninstall_tidb_pool $TEST_ENV "$RANDOM_CLUSTER"
    $ROOT/hack/pulumi/deploy.sh uninstall_manager $TEST_ENV "$RANDOM_CLUSTER"
}

# always re-deploy all components
if [[ $MODE == "auto" ]]; then
    SKIP_DEPLOY=0
    FOCUS=".*"
    SELECTOR="For=Core"
    TEST_ENV="dev-eks"
fi

# Get RDS config from cloud secret and export its
e2e::load_aws_rds_credentials

# Assignment for MySQL operations
MYSQL_DB_PORT="${RDS_PORT}"
MYSQL_DB_USER="${RDS_USERNAME}"
MYSQL_DB_PASSWORD="${RDS_PASSWORD}"
MYSQL_DB_NAME="${RDS_DBNAME}"

trap e2e::stop_rds_tunnel EXIT HUP INT QUIT TERM

if [[ $CLEANUP == 1 ]]; then
    if ! $KUBECTL get ns "${MANAGER_NS}" \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT} >/dev/null 2>&1; then
        exit
    fi

    $KUBECTL delete ns \
        --kubeconfig=${FREE_TIER_KUBECONFIG} \
        --context=${FREE_TIER_CONTEXT} \
        -l testing.tidbcloud.com/for=e2e,testing.tidbcloud.com/e2e-id="${RANDOM_CLUSTER}"
    e2e::start_rds_tunnel
    e2e::cleanup
    exit
fi

if [[ $SKIP_DEPLOY == 0 ]]; then
    $ROOT/hack/pulumi/deploy.sh install_manager $TEST_ENV "$RANDOM_CLUSTER" "$TIDB_POOL_NS"
    $ROOT/hack/pulumi/deploy.sh install_tidb_pool $TEST_ENV "$RANDOM_CLUSTER"
    $ROOT/hack/pulumi/deploy.sh install_gateway $TEST_ENV "$RANDOM_CLUSTER"
    $ROOT/hack/pulumi/deploy.sh install_tidb_worker $TEST_ENV "$RANDOM_CLUSTER"
fi

e2e::start_rds_tunnel

$GINKGO \
    -v \
    --poll-progress-after=${GINKGO_POLL_PROGRESS_AFTER} \
    --poll-progress-interval=${GINKGO_POLL_PROGRESS_INTERVAL} \
    --nodes=4 \
    $ROOT/tests \
    -- \
    --kubeconfig=${FREE_TIER_KUBECONFIG} \
    --context=${FREE_TIER_CONTEXT} \
    --infra-cluster-table=${INFRA_CLUSTER_TABLE} \
    --aws-region=${VAR_AWS_REGION} \
    --tidb-pool-ns="${TIDB_POOL_NS}" \
    --kube-cluster-name-base="${RANDOM_CLUSTER}" \
    --selector="${SELECTOR}" \
    --test.timeout=1h
$GINKGO \
    -v \
    --poll-progress-after=${GINKGO_POLL_PROGRESS_AFTER} \
    --poll-progress-interval=${GINKGO_POLL_PROGRESS_INTERVAL} \
    --nodes=4 \
    $ROOT/tests/apie2e \
    -- \
    --infra-cluster-table=${INFRA_CLUSTER_TABLE} \
    --kube-config=${FREE_TIER_KUBECONFIG} \
    --kube-context=${FREE_TIER_CONTEXT} \
    --eks-kube-config=${FREE_TIER_KUBECONFIG} \
    --eks-kube-context=${FREE_TIER_CONTEXT} \
    --kube-label="${RANDOM_CLUSTER}" \
    --aws-region=${VAR_AWS_REGION} \
    --namespace="${RANDOM_CLUSTER}" \
    --manager-ns="${MANAGER_NS}" \
    --vip-tidb-pool="${VIP_TIDB_POOL_NS}" \
    --ginkgo.focus=${FOCUS} \
    --test.timeout=1h

# clean environment if MODE is auto
if [[ $MODE == "auto" ]]; then
    e2e::cleanup
fi
