#!/bin/bash
# Common diff functions for component diff scripts
# Source this file in component-specific diff.sh scripts

# Track if any changes found (shared across all diff operations)
CHANGES_FOUND=false

# Output file for diff results (set by caller)
DIFF_OUTPUT_FILE=""

# Function to write output to file or stdout
write_output() {
  if [ -n "$DIFF_OUTPUT_FILE" ]; then
    printf '%s\n' "$1" >>"$DIFF_OUTPUT_FILE"
  else
    printf '%s\n' "$1"
  fi
}

# Initialize diff output file
# Args: $1 = output file path (optional)
init_diff_output() {
  local output_file="${1:-}"
  DIFF_OUTPUT_FILE="$output_file"
  CHANGES_FOUND=false

  if [ -n "$DIFF_OUTPUT_FILE" ]; then
    >"$DIFF_OUTPUT_FILE"
  fi
}

# Function to filter out noisy metadata changes from diff output
# These fields change on every update and don't represent meaningful changes
filter_diff_noise() {
  grep -v -E \
    -e '^\+.*generation:' \
    -e '^-.*generation:' \
    -e '^\+.*resourceVersion:' \
    -e '^-.*resourceVersion:' \
    -e '^\+.*uid:' \
    -e '^-.*uid:' \
    -e '^\+.*creationTimestamp:' \
    -e '^-.*creationTimestamp:' \
    -e '^\+.*kubectl.kubernetes.io/last-applied-configuration:' \
    -e '^-.*kubectl.kubernetes.io/last-applied-configuration:' \
    -e '^\+.*time:' \
    -e '^-.*time:' ||
    true
}

# Check if filtered diff has meaningful changes (not just metadata noise)
has_meaningful_changes() {
  local diff_content="$1"
  # Count lines that start with + or - (actual changes) excluding --- and +++
  local change_count
  change_count=$(echo "$diff_content" | grep -c -E '^[+-][^+-]' || echo "0")
  [ "$change_count" -gt 0 ]
}

# Function to perform kubectl diff with minimal output
# Args: $1 = resource path (file or directory), $2 = component name for display
kubectl_diff() {
  local resource_path="$1"
  local component_name="$2"

  if [ ! -d "$resource_path" ] && [ ! -f "$resource_path" ]; then
    write_output "❌ $component_name: Resource not found"
    return 1
  fi

  local diff_output
  local filtered_output
  local exit_code=0
  local tmp_file="/tmp/kubectl_diff_output_$$"

  if kubectl diff --show-managed-fields=false -f "$resource_path" >"$tmp_file" 2>&1; then
    diff_output=$(cat "$tmp_file")
    if [ -z "$diff_output" ]; then
      write_output "✅ $component_name: No changes"
    else
      # Filter out noisy metadata changes
      filtered_output=$(echo "$diff_output" | filter_diff_noise)
      if ! has_meaningful_changes "$filtered_output"; then
        write_output "✅ $component_name: No changes (metadata only)"
      else
        CHANGES_FOUND=true
        write_output "🔄 $component_name: Changes detected"
        write_output "<details><summary>View diff</summary>"
        write_output ""
        write_output '```diff'
        write_output "$filtered_output"
        write_output '```'
        write_output "</details>"
        write_output ""
      fi
    fi
  else
    exit_code=$?
    diff_output=$(cat "$tmp_file")

    if [ $exit_code -eq 1 ]; then
      # Filter out noisy metadata changes
      filtered_output=$(echo "$diff_output" | filter_diff_noise)
      if ! has_meaningful_changes "$filtered_output"; then
        write_output "✅ $component_name: No changes (metadata only)"
      else
        CHANGES_FOUND=true
        write_output "🔄 $component_name: Changes detected"
        write_output "<details><summary>View diff</summary>"
        write_output ""
        write_output '```diff'
        write_output "$filtered_output"
        write_output '```'
        write_output "</details>"
        write_output ""
      fi
    else
      write_output "❌ $component_name: Error (exit code: $exit_code)"
    fi
  fi

  rm -f "$tmp_file"
}

# Function to perform helm diff with minimal output
# Args: $1 = release name, $2 = chart path, $3 = values file, $4 = namespace,
#       $5 = component name for display, $6 = chart version (optional)
helm_diff() {
  local release_name="$1"
  local chart_path="$2"
  local values_file="$3"
  local namespace="$4"
  local component_name="$5"
  local chart_version="${6:-}"
  local -a extra_args=()

  if [ "$#" -gt 6 ]; then
    extra_args=("${@:7}")
  fi

  if [ ! -f "$values_file" ]; then
    write_output "❌ $component_name: Values file not found"
    return 1
  fi

  if ! helm plugin list | grep -q "diff"; then
    helm plugin install https://github.com/databus23/helm-diff --verify=false >/dev/null 2>&1 || {
      write_output "❌ $component_name: Failed to install helm-diff plugin"
      return 1
    }
  fi

  # Build helm diff command
  # dyff is more precise than diff
  local -a helm_cmd=(
    helm diff upgrade "$release_name" "$chart_path" -n "$namespace" -f "$values_file"
    --allow-unreleased
    --take-ownership
    --output dyff
  )
  if [ -n "$chart_version" ]; then
    helm_cmd+=(--version "$chart_version")
  fi
  if [ "${#extra_args[@]}" -gt 0 ]; then
    helm_cmd+=("${extra_args[@]}")
  fi

  local diff_output
  local error_output
  local exit_code=0
  local tmp_file="/tmp/helm_diff_output_$$"

  if "${helm_cmd[@]}" >"$tmp_file" 2>&1; then
    diff_output=$(cat "$tmp_file")
    if [ -z "$diff_output" ] || echo "$diff_output" | grep -q "has no changes"; then
      write_output "✅ $component_name: No changes"
    else
      CHANGES_FOUND=true
      write_output "🔄 $component_name: Changes detected"
      write_output "<details><summary>View diff</summary>"
      write_output ""
      write_output '```diff'
      write_output "$diff_output"
      write_output '```'
      write_output "</details>"
      write_output ""
    fi
  else
    exit_code=$?
    diff_output=$(cat "$tmp_file")

    if echo "$diff_output" | grep -q "release.*not found"; then
      CHANGES_FOUND=true
      write_output "🆕 $component_name: New installation"
      write_output "<details><summary>View template preview</summary>"
      write_output ""
      write_output '```yaml'
      helm template "$release_name" "$chart_path" -n "$namespace" -f "$values_file" ${chart_version:+--version "$chart_version"} 2>/dev/null | head -50
      write_output '```'
      write_output "</details>"
      write_output ""
    else
      local helm_cmd_string
      printf -v helm_cmd_string '%q ' "${helm_cmd[@]}"
      helm_cmd_string="${helm_cmd_string% }"
      error_output=$(printf '%s\n' "$diff_output" | tail -n 80)

      write_output "❌ $component_name: Error (exit code: $exit_code)"
      write_output "<details><summary>View error</summary>"
      write_output ""
      write_output "**Command:** \`$helm_cmd_string\`"
      write_output ""
      write_output '```text'
      write_output "$error_output"
      write_output '```'
      write_output "</details>"
      write_output ""

    fi
  fi

  rm -f "$tmp_file"
}

# Write diff summary
# Returns 0 on successful summary generation (regardless of whether changes exist)
write_diff_summary() {
  write_output ""
  if [ "$CHANGES_FOUND" = true ]; then
    write_output "⚠️ **Changes detected** - Review carefully before deployment"
    return 0
  else
    write_output "✅ **No changes** - All components are up to date"
    return 0
  fi
}

# Parse common arguments for diff scripts
# Sets: VENDOR, ENV, REGION, LOGICAL_REGION, OUTPUT_FILE
# Args: $1 = vendor, $2 = env, $3 = region, $4 = logical_region, $5 = output_file (optional)
parse_diff_args() {
  VENDOR=${1:-"aws"}
  ENV=${2:-"dev"}
  REGION=${3:-""}
  LOGICAL_REGION=${4:-"$REGION"}
  OUTPUT_FILE=${5:-""}

  if [ -z "$VENDOR" ] || [ -z "$ENV" ] || [ -z "$REGION" ] || [ -z "$LOGICAL_REGION" ]; then
    echo "Error: Missing required arguments."
    echo "Usage: $0 <vendor> <env> <region> <logical_region> [output_file]"
    exit 1
  fi

  # Initialize output
  init_diff_output "$OUTPUT_FILE"
}

# Ensure kubeconfig has proper permissions
ensure_kubeconfig_permissions() {
  if [ -f ~/.kube/config ]; then
    chmod go-r ~/.kube/config
  fi
}
