#!/usr/bin/env bash
set -euo pipefail

OWNER_ALIAS="${OWNER_ALIAS:-}"
LOCATION="${LOCATION:-eastus}"
CLUSTER_FLAVOR="${CLUSTER_FLAVOR:-aks}"
TF_STATE_KEY="${TF_STATE_KEY:-sre-simulator.tfstate}"
GENEVA_SUPPRESSION_ACCESS_CONFIRMED="${GENEVA_SUPPRESSION_ACCESS_CONFIRMED:-false}"
SQL_SERVER_NAME="${SQL_SERVER_NAME:-}"
TF_STATE_RG="${TF_STATE_RG:-tfstate-rg}"
TF_STATE_ACCOUNT="${TF_STATE_ACCOUNT:-}"
TF_STATE_CONTAINER="${TF_STATE_CONTAINER:-tfstate}"
TF_BACKEND_ENV_FILE="${TF_BACKEND_ENV_FILE:-.tf-backend.env}"
AOAI_MODEL_NAME="${AOAI_MODEL_NAME:-gpt-5.6-terra}"
AOAI_MODEL_VERSION="${AOAI_MODEL_VERSION:-2026-07-09}"
AOAI_SKU_NAME="${AOAI_SKU_NAME:-GlobalStandard}"
ENABLE_SQL_FREE_TIER="${ENABLE_SQL_FREE_TIER:-false}"
AKS_NODE_RESOURCE_GROUP_NAME="${AKS_NODE_RESOURCE_GROUP_NAME:-}"

failures=()
warnings=()

add_failure() {
  failures+=("$1")
}

add_warning() {
  warnings+=("$1")
}

require_command() {
  local command_name=$1
  if ! command -v "$command_name" >/dev/null 2>&1; then
    add_failure "Missing required command: ${command_name}"
  fi
}

contains_role() {
  local roles=$1
  local expected=$2
  local role
  while IFS= read -r role; do
    if [[ "$role" == "$expected" ]]; then
      return 0
    fi
  done <<<"$roles"
  return 1
}

is_tty() {
  [[ -t 0 ]]
}

is_yes() {
  local answer="${1:-}"
  answer="$(echo "$answer" | tr '[:upper:]' '[:lower:]')"
  [[ "$answer" == "y" || "$answer" == "yes" ]]
}

is_valid_storage_account_name() {
  local name="${1:-}"
  [[ "$name" =~ ^[a-z0-9]{3,24}$ ]]
}

prompt_yes_no() {
  local prompt="$1"
  local response
  read -r -p "$prompt" response
  is_yes "$response"
}

persist_backend_env() {
  cat >"$TF_BACKEND_ENV_FILE" <<EOF
# Generated by tf-preflight. Safe to edit if needed.
LOCATION=${LOCATION}
TF_STATE_RG=${TF_STATE_RG}
TF_STATE_ACCOUNT=${TF_STATE_ACCOUNT}
TF_STATE_CONTAINER=${TF_STATE_CONTAINER}
TF_STATE_KEY=${TF_STATE_KEY}
EOF
  echo "Persisted backend defaults to ${TF_BACKEND_ENV_FILE}"
}

ensure_state_backend_exists() {
  local storage_account_exists container_exists

  if [[ -z "$TF_STATE_ACCOUNT" ]]; then
    if is_tty; then
      echo "Terraform remote state account is not configured (TF_STATE_ACCOUNT is empty)."
      if prompt_yes_no "First-time run: create Terraform backend resources now? [y/N] "; then
        while true; do
          read -r -p "Enter globally unique TF_STATE_ACCOUNT name (3-24 chars, lowercase letters/numbers only): " TF_STATE_ACCOUNT
          if is_valid_storage_account_name "$TF_STATE_ACCOUNT"; then
            break
          fi
          echo "Invalid storage account name: ${TF_STATE_ACCOUNT}"
          echo "Use 3-24 chars with only lowercase letters and numbers (no dashes)."
          echo "Example: aaffinitsresimulator"
        done
      else
        add_failure "TF_STATE_ACCOUNT is required. Set it or run: make tf-bootstrap TF_STATE_ACCOUNT=<name>"
        return
      fi
    else
      add_failure "TF_STATE_ACCOUNT is required. Set it or run interactively to create backend resources."
      return
    fi
  fi

  if ! is_valid_storage_account_name "$TF_STATE_ACCOUNT"; then
    add_failure "TF_STATE_ACCOUNT must be 3-24 lowercase letters/numbers with no dashes. Example: aaffinitsresimulator"
    return
  fi

  storage_account_exists=false
  if az storage account show --name "$TF_STATE_ACCOUNT" --resource-group "$TF_STATE_RG" >/dev/null 2>&1; then
    storage_account_exists=true
  fi

  if [[ "$storage_account_exists" != "true" ]]; then
    if is_tty && prompt_yes_no "State storage account ${TF_STATE_ACCOUNT} not found in ${TF_STATE_RG}. Create it now in ${LOCATION}? [y/N] "; then
      az group create --name "$TF_STATE_RG" --location "$LOCATION" --tags purpose=terraform-state >/dev/null
      az storage account create \
        --name "$TF_STATE_ACCOUNT" \
        --resource-group "$TF_STATE_RG" \
        --location "$LOCATION" \
        --sku Standard_LRS \
        --min-tls-version TLS1_2 \
        --allow-blob-public-access false \
        --tags purpose=terraform-state >/dev/null
      echo "Created Terraform state storage account: ${TF_STATE_ACCOUNT}"
    else
      add_failure "State storage account ${TF_STATE_ACCOUNT} was not found. Create it with: make tf-bootstrap TF_STATE_ACCOUNT=${TF_STATE_ACCOUNT} LOCATION=${LOCATION}"
      return
    fi
  fi

  container_exists=false
  if az storage container show \
    --name "$TF_STATE_CONTAINER" \
    --account-name "$TF_STATE_ACCOUNT" \
    --auth-mode login >/dev/null 2>&1; then
    container_exists=true
  fi

  if [[ "$container_exists" != "true" ]]; then
    if is_tty && prompt_yes_no "State container ${TF_STATE_CONTAINER} not found in ${TF_STATE_ACCOUNT}. Create it now? [y/N] "; then
      az storage container create \
        --name "$TF_STATE_CONTAINER" \
        --account-name "$TF_STATE_ACCOUNT" \
        --auth-mode login >/dev/null
      echo "Created Terraform state container: ${TF_STATE_CONTAINER}"
    else
      add_failure "State container ${TF_STATE_CONTAINER} was not found in ${TF_STATE_ACCOUNT}. Create it with: az storage container create --name ${TF_STATE_CONTAINER} --account-name ${TF_STATE_ACCOUNT} --auth-mode login"
      return
    fi
  fi
}

echo "== Kubernetes final infra preflight =="
echo "Owner alias: ${OWNER_ALIAS:-<missing>}"
echo "Location: ${LOCATION}"
echo "Cluster flavor: ${CLUSTER_FLAVOR}"
echo "State key: ${TF_STATE_KEY}"
echo "State account: ${TF_STATE_ACCOUNT:-<missing>}"
echo "State resource group: ${TF_STATE_RG}"
echo "State container: ${TF_STATE_CONTAINER}"
echo "Backend env file: ${TF_BACKEND_ENV_FILE}"
echo "SQL server name: ${SQL_SERVER_NAME:-<default from alias>}"
echo "AOAI model/version: ${AOAI_MODEL_NAME}/${AOAI_MODEL_VERSION}"
echo "AOAI deployment sku: ${AOAI_SKU_NAME}"
echo "Enable SQL free tier: ${ENABLE_SQL_FREE_TIER}"
if [[ "$CLUSTER_FLAVOR" == "aks" ]]; then
  echo "AKS node resource group override: ${AKS_NODE_RESOURCE_GROUP_NAME:-<default>}"
fi
echo

if [[ -z "$OWNER_ALIAS" ]]; then
  add_failure "OWNER_ALIAS is required (expected aaffinit for final environment)."
elif [[ ! "$OWNER_ALIAS" =~ ^[a-z][a-z0-9]{2,15}$ ]]; then
  add_failure "OWNER_ALIAS must match ^[a-z][a-z0-9]{2,15}$."
fi

if [[ "$CLUSTER_FLAVOR" != "aks" && "$CLUSTER_FLAVOR" != "aro" ]]; then
  add_failure "CLUSTER_FLAVOR must be either aks or aro."
fi

if [[ "$OWNER_ALIAS" != "aaffinit" ]]; then
  add_failure "OWNER_ALIAS must be aaffinit for the final environment naming convention."
fi

if [[ "$TF_STATE_KEY" == "sre-simulator.tfstate" ]]; then
  add_failure "TF_STATE_KEY uses the shared default. Use an isolated key (example: aaffinit-test-sre-simulator.tfstate)."
fi

if [[ "$TF_STATE_KEY" != *"${OWNER_ALIAS}"* ]]; then
  add_warning "TF_STATE_KEY does not contain owner alias; verify this is intentional."
fi

require_command "az"
require_command "terraform"

if ((${#failures[@]} == 0)); then
  if ! az account show >/dev/null 2>&1; then
    add_failure "Azure CLI is not authenticated. Run: az login"
  fi
fi

if ((${#failures[@]} == 0)); then
  ensure_state_backend_exists
fi

subscription_id=""
assignee=""
if ((${#failures[@]} == 0)); then
  subscription_id="$(az account show --query id -o tsv)"
  assignee="$(az account show --query user.name -o tsv)"

  echo "Subscription: ${subscription_id}"
  echo "Assignee: ${assignee}"
  echo

  role_names="$(az role assignment list \
    --assignee "$assignee" \
    --scope "/subscriptions/${subscription_id}" \
    --include-inherited \
    --query "[].roleDefinitionName" \
    -o tsv 2>/dev/null || true)"

  if [[ -z "$role_names" ]]; then
    add_warning "Could not enumerate role assignments for ${assignee}; confirm permissions manually."
  else
    if ! contains_role "$role_names" "Owner" && ! contains_role "$role_names" "Contributor"; then
      add_failure "Missing Owner/Contributor at subscription scope; Terraform apply may fail."
    fi
    if ! contains_role "$role_names" "Owner" && ! contains_role "$role_names" "User Access Administrator"; then
      add_warning "No Owner/User Access Administrator detected; role assignment resources may fail."
    fi
  fi

  providers=(
    Microsoft.Compute
    Microsoft.Network
    Microsoft.Sql
    Microsoft.CognitiveServices
  )
  if [[ "$CLUSTER_FLAVOR" == "aro" ]]; then
    providers+=(Microsoft.RedHatOpenShift)
  else
    providers+=(Microsoft.ContainerService)
  fi

  for provider in "${providers[@]}"; do
    state="$(az provider show --namespace "$provider" --query registrationState -o tsv 2>/dev/null || true)"
    if [[ "$state" != "Registered" ]]; then
      add_failure "Resource provider ${provider} is not Registered (state=${state:-unknown})."
    fi
  done

  app_rg="${OWNER_ALIAS}-test-rg"
  if [[ "$CLUSTER_FLAVOR" == "aro" ]]; then
    managed_rg="${OWNER_ALIAS}-test-cluster-rg"
  else
    managed_rg="${AKS_NODE_RESOURCE_GROUP_NAME:-${OWNER_ALIAS}-test-aks-nodes-rg}"
  fi
  sql_server_name="${SQL_SERVER_NAME:-${OWNER_ALIAS}-test-sql}"

  app_rg_exists="$(az group exists --name "$app_rg" 2>/dev/null || echo false)"
  if [[ "$app_rg_exists" == "true" ]]; then
    add_failure "Resource group ${app_rg} already exists. This risks side effects on existing resources."
  fi

  managed_rg_exists="$(az group exists --name "$managed_rg" 2>/dev/null || echo false)"
  if [[ "$managed_rg_exists" == "true" ]]; then
    if [[ "$CLUSTER_FLAVOR" == "aro" ]]; then
      add_failure "Cluster resource group ${managed_rg} already exists. Clean up or choose a different alias/suffix."
    else
      add_failure "AKS node resource group ${managed_rg} already exists. Clean up or choose a different alias/suffix."
    fi
  fi

  sql_name_check="$(az rest \
    --method post \
    --url "https://management.azure.com/subscriptions/${subscription_id}/providers/Microsoft.Sql/checkNameAvailability?api-version=2021-11-01" \
    --body "{\"name\":\"${sql_server_name}\",\"type\":\"Microsoft.Sql/servers\"}" \
    --query "{available:nameAvailable,message:message}" \
    -o tsv 2>/dev/null || true)"
  sql_name_available="$(printf '%s\n' "$sql_name_check" | awk 'NR==1 {print $1}')"
  sql_name_message="$(printf '%s\n' "$sql_name_check" | cut -f2-)"
  if [[ -z "$sql_name_available" ]]; then
    add_warning "Could not verify global SQL server name availability for ${sql_server_name}; check manually."
  elif [[ "$sql_name_available" != "true" ]]; then
    if [[ -n "$sql_name_message" ]]; then
      add_failure "SQL server name ${sql_server_name} is not available: ${sql_name_message}"
    else
      add_failure "SQL server name ${sql_server_name} is not globally available."
    fi
  fi

  if [[ "$CLUSTER_FLAVOR" == "aro" ]]; then
    latest_aro_version="$(az aro get-versions --location "$LOCATION" --query "[-1]" -o tsv 2>/dev/null || true)"
    if [[ -z "$latest_aro_version" ]]; then
      add_warning "Could not resolve latest ARO version. Verify az aro extension and region support."
    else
      echo "Latest reported ARO version in ${LOCATION}: ${latest_aro_version}"
    fi

    dsv3_quota="$(az vm list-usage --location "$LOCATION" \
      --query "[?contains(name.localizedValue, 'DSv3') || contains(name.value, 'DSv3')].[name.localizedValue, currentValue, limit]" \
      -o tsv 2>/dev/null || true)"
    if [[ -z "$dsv3_quota" ]]; then
      add_warning "Could not resolve DSv3 quota usage for ${LOCATION}. Check compute quotas manually."
    else
      echo
      echo "DSv3 quota usage (name current limit):"
      echo "$dsv3_quota"
    fi
  else
    bseries_quota="$(az vm list-usage --location "$LOCATION" \
      --query "[?contains(name.localizedValue, 'B-Series') || contains(name.value, 'BS')].[name.localizedValue, currentValue, limit]" \
      -o tsv 2>/dev/null || true)"
    if [[ -z "$bseries_quota" ]]; then
      add_warning "Could not resolve B-series quota usage for ${LOCATION}. Check compute quotas manually."
    else
      echo
      echo "B-series quota usage (name current limit):"
      echo "$bseries_quota"
    fi
  fi

  aoai_skus="$(az cognitiveservices model list \
    --location "$LOCATION" \
    --query "[?kind=='OpenAI' && model.name=='${AOAI_MODEL_NAME}' && model.version=='${AOAI_MODEL_VERSION}'].model.skus[].name" \
    -o tsv 2>/dev/null || true)"
  if [[ -z "$aoai_skus" ]]; then
    add_failure "AOAI model ${AOAI_MODEL_NAME} version ${AOAI_MODEL_VERSION} was not found in ${LOCATION}. Query available models with: az cognitiveservices model list --location ${LOCATION} --query \"[?kind=='OpenAI'].model.[name,version]\" -o tsv"
  elif ! contains_role "$aoai_skus" "$AOAI_SKU_NAME"; then
    add_failure "AOAI sku ${AOAI_SKU_NAME} is not supported for ${AOAI_MODEL_NAME} ${AOAI_MODEL_VERSION} in ${LOCATION}. Available skus: $(echo "$aoai_skus" | tr '\n' ' ')"
  fi

  if [[ "$ENABLE_SQL_FREE_TIER" == "true" ]]; then
    add_warning "enable_sql_free_tier=true may fail in some regions/subscriptions (error: ProvisioningDisabled). Disable if apply fails."
  fi
fi

if [[ "$CLUSTER_FLAVOR" == "aro" && "$GENEVA_SUPPRESSION_ACCESS_CONFIRMED" != "true" ]]; then
  add_failure "Geneva suppression access was not confirmed for the ARO path. Set GENEVA_SUPPRESSION_ACCESS_CONFIRMED=true after validating access."
fi

echo
echo "Recommended terraform values:"
echo "  owner_alias = \"aaffinit\""
echo "  cluster_flavor = \"${CLUSTER_FLAVOR}\""
if [[ "$CLUSTER_FLAVOR" == "aro" ]]; then
  echo "  master_vm_size = \"Standard_D8s_v3\""
  echo "  worker_vm_size = \"Standard_D4s_v3\""
  echo "  worker_count = 2"
  echo "  aro_version = \"${latest_aro_version:-<pin-latest-compatible>}\""
else
  echo "  aks_node_vm_size = \"Standard_B2s\""
  echo "  aks_node_count_min = 1"
  echo "  aks_node_count_max = 3"
  echo "  aks_public_ip_dns_label = \"aaffinit-test\""
  if [[ -n "$AKS_NODE_RESOURCE_GROUP_NAME" ]]; then
    echo "  aks_node_resource_group_name = \"${AKS_NODE_RESOURCE_GROUP_NAME}\""
  fi
fi
echo "  aoai_model_name = \"${AOAI_MODEL_NAME}\""
echo "  aoai_model_version = \"${AOAI_MODEL_VERSION}\""
echo "  aoai_sku_name = \"${AOAI_SKU_NAME}\""
echo "  enable_database = true"
echo "  enable_sql_free_tier = ${ENABLE_SQL_FREE_TIER}"
echo "  sql_server_name = \"${SQL_SERVER_NAME:-${OWNER_ALIAS}-test-sql}\""
echo "  extra_tags = { test = \"true\" }"

if ((${#warnings[@]} > 0)); then
  echo
  echo "Warnings:"
  for warning in "${warnings[@]}"; do
    echo "  - ${warning}"
  done
fi

if ((${#failures[@]} > 0)); then
  echo
  echo "Preflight failed:"
  for failure in "${failures[@]}"; do
    echo "  - ${failure}"
  done
  exit 1
fi

persist_backend_env

echo
echo "Preflight passed."
