#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# rollback.sh – Rollback deployments for Claude Code Agent Monitor
#
# Usage:
#   ./rollback.sh --env production --method helm --revision 5
#   ./rollback.sh --env staging --method kustomize
#   ./rollback.sh --help
# ─────────────────────────────────────────────────────────────────────────────
# @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
set -euo pipefail

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly APP_NAME="agent-monitor"
readonly APP_PORT=4820

# ── Colors & logging ───────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

log()   { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*"; }
info()  { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${BLUE}ℹ${NC}  $*"; }
ok()    { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${GREEN}✔${NC}  $*"; }
warn()  { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${YELLOW}⚠${NC}  $*" >&2; }
err()   { echo -e "${CYAN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} ${RED}✖${NC}  $*" >&2; }
fatal() { err "$@"; exit 1; }

# ── Defaults ────────────────────────────────────────────────────────────────
ENVIRONMENT=""
METHOD=""
REVISION=""
NAMESPACE=""
HELM_RELEASE="${APP_NAME}"
SKIP_HEALTH_CHECK=false

# ── Usage ───────────────────────────────────────────────────────────────────
usage() {
  cat <<EOF
${BOLD}Usage:${NC}
  $(basename "$0") --env <environment> --method <method> [options]

${BOLD}Required:${NC}
  --env, -e          Environment: dev, staging, production
  --method, -m       Method: helm, kustomize

${BOLD}Options:${NC}
  --revision, -r     Helm revision or rollout history number to roll back to
  --namespace, -n    Kubernetes namespace (default: agent-monitor-<env>)
  --release          Helm release name (default: ${APP_NAME})
  --skip-health      Skip post-rollback health check
  --help, -h         Show this help message

${BOLD}Examples:${NC}
  $(basename "$0") --env production --method helm --revision 5
  $(basename "$0") --env staging --method kustomize
  $(basename "$0") --env production --method helm  # rolls back to previous

EOF
  exit 0
}

# ── Argument parsing ────────────────────────────────────────────────────────
parse_args() {
  [[ $# -eq 0 ]] && usage

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --env|-e)         ENVIRONMENT="$2"; shift 2 ;;
      --method|-m)      METHOD="$2"; shift 2 ;;
      --revision|-r)    REVISION="$2"; shift 2 ;;
      --namespace|-n)   NAMESPACE="$2"; shift 2 ;;
      --release)        HELM_RELEASE="$2"; shift 2 ;;
      --skip-health)    SKIP_HEALTH_CHECK=true; shift ;;
      --help|-h)        usage ;;
      *)                fatal "Unknown option: $1" ;;
    esac
  done

  [[ -z "$ENVIRONMENT" ]] && fatal "Missing required argument: --env"
  [[ -z "$METHOD" ]]      && fatal "Missing required argument: --method"
  [[ -z "$NAMESPACE" ]]   && NAMESPACE="agent-monitor-${ENVIRONMENT}"
}

# ── Show release history ───────────────────────────────────────────────────
show_history() {
  info "Release history:"
  case "$METHOD" in
    helm)
      helm history "${HELM_RELEASE}" -n "${NAMESPACE}" --max 10 2>/dev/null || warn "No history found"
      ;;
    kustomize)
      kubectl rollout history "deployment/${APP_NAME}" -n "${NAMESPACE}" 2>/dev/null || warn "No history found"
      ;;
  esac
  echo ""
}

# ── Confirm rollback ───────────────────────────────────────────────────────
confirm_rollback() {
  if [[ "$ENVIRONMENT" == "production" ]]; then
    local target_msg="previous revision"
    [[ -n "$REVISION" ]] && target_msg="revision ${REVISION}"

    warn "Rolling back ${BOLD}PRODUCTION${NC} to ${target_msg}"
    read -r -p "$(echo -e "${YELLOW}Type 'yes' to confirm:${NC} ")" confirm
    [[ "$confirm" == "yes" ]] || fatal "Rollback cancelled."
  fi
}

# ── Helm rollback ───────────────────────────────────────────────────────────
rollback_helm() {
  info "Rolling back Helm release '${HELM_RELEASE}' in namespace '${NAMESPACE}'..."

  local rollback_args=(rollback "${HELM_RELEASE}")
  [[ -n "$REVISION" ]] && rollback_args+=("${REVISION}")
  rollback_args+=(-n "${NAMESPACE}" --wait --timeout 300s)

  if ! helm "${rollback_args[@]}"; then
    fatal "Helm rollback failed! Manual intervention required."
  fi

  ok "Helm rollback completed"

  # Show current status
  info "Current release status:"
  helm status "${HELM_RELEASE}" -n "${NAMESPACE}" 2>/dev/null || true
}

# ── Kustomize rollback ─────────────────────────────────────────────────────
rollback_kustomize() {
  info "Rolling back deployment '${APP_NAME}' in namespace '${NAMESPACE}'..."

  local undo_args=(rollout undo "deployment/${APP_NAME}" -n "${NAMESPACE}")
  if [[ -n "$REVISION" ]]; then
    undo_args+=(--to-revision="${REVISION}")
  fi

  if ! kubectl "${undo_args[@]}"; then
    fatal "Kubectl rollback failed! Manual intervention required."
  fi

  # Wait for rollout
  info "Waiting for rollout to complete..."
  if ! kubectl rollout status "deployment/${APP_NAME}" -n "${NAMESPACE}" --timeout=300s; then
    fatal "Rollout did not complete in time!"
  fi

  ok "Kustomize rollback completed"
}

# ── Post-rollback health check ─────────────────────────────────────────────
run_health_check() {
  if [[ "$SKIP_HEALTH_CHECK" == true ]]; then
    info "Skipping health check"
    return
  fi

  info "Running post-rollback health check..."

  # Wait for pods to be ready
  if ! kubectl wait --for=condition=ready pod \
      -l "app.kubernetes.io/name=${APP_NAME}" \
      -n "${NAMESPACE}" --timeout=120s 2>/dev/null; then
    fatal "Pods did not become ready after rollback!"
  fi

  # Use health-check.sh if available
  if [[ -x "${SCRIPT_DIR}/health-check.sh" ]]; then
    # Port forward for check
    local local_port=14820
    kubectl port-forward "svc/${APP_NAME}" "${local_port}:${APP_PORT}" -n "${NAMESPACE}" &
    local pf_pid=$!
    sleep 3

    if "${SCRIPT_DIR}/health-check.sh" --url "http://localhost:${local_port}" --retries 10 --interval 3; then
      ok "Health check passed after rollback"
    else
      err "Health check failed after rollback!"
    fi

    kill "$pf_pid" 2>/dev/null || true
  else
    ok "Pods are ready"
  fi
}

# ── Main ────────────────────────────────────────────────────────────────────
main() {
  echo ""
  echo -e "${BOLD}${YELLOW}╔══════════════════════════════════════════════════╗${NC}"
  echo -e "${BOLD}${YELLOW}║   Claude Code Agent Monitor – Rollback          ║${NC}"
  echo -e "${BOLD}${YELLOW}╚══════════════════════════════════════════════════╝${NC}"
  echo ""

  parse_args "$@"
  show_history
  confirm_rollback

  case "$METHOD" in
    helm)       rollback_helm ;;
    kustomize)  rollback_kustomize ;;
    *)          fatal "Rollback not supported for method: ${METHOD}" ;;
  esac

  run_health_check

  echo ""
  ok "${BOLD}Rollback complete!${NC}"
  echo -e "  ${BOLD}Environment:${NC}  ${ENVIRONMENT}"
  echo -e "  ${BOLD}Method:${NC}       ${METHOD}"
  echo -e "  ${BOLD}Revision:${NC}     ${REVISION:-previous}"
  echo -e "  ${BOLD}Timestamp:${NC}    $(date -u +%Y-%m-%dT%H:%M:%SZ)"
  echo ""
}

main "$@"
