# Handle dependency extensions
handle_dependency_extensions() {
  local formula=$1
  local extension=$2
  formula_file="${tap_dir:?}/$ext_tap/Formula/$extension@${version:?}.rb"
  [ -e "$formula_file" ] || formula_file="$tap_dir/$ext_tap/Formula/$formula@$version.rb"
  if [ -e "$formula_file" ]; then
    IFS=" " read -r -a dependency_extensions <<< "$(grep -Eo "shivammathur.*@" "$formula_file" | xargs -I {} -n 1 basename '{}' | cut -d '@' -f 1 | tr '\n' ' ')"
    for dependency_extension in "${dependency_extensions[@]}"; do
      sudo sed -Ei '' "/=(.*\/)?\"?$dependency_extension(.so)?$/d" "${ini_file:?}"
    done
  fi
  suffix="$(get_php_formula_suffix)"
  if [[ -n "$suffix" ]]; then
    brew_opts=(-sf)
    patch_abstract_file >/dev/null 2>&1
    for dependency_extension in "${dependency_extensions[@]}"; do
        safe_brew install --skip-link "${brew_opts[@]}" "$ext_tap/$dependency_extension@$version" >/dev/null 2>&1 &&
        brew link --overwrite --force "$dependency_extension@$version" >/dev/null 2>&1 &&
        copy_brew_extensions "$dependency_extension"
    done
  fi
}

# Helper function to disable an extension.
disable_extension_helper() {
  local extension=$1
  local disable_dependents=${2:-false}
  get_extension_map
  if [ "$disable_dependents" = "true" ]; then
    disable_extension_dependents "$extension"
  fi
  sudo sed -Ei '' "/=(.*\/)?\"?$extension(.so)?$/d" "${ini_file:?}"
  sudo rm -rf "$scan_dir"/*"$extension"* /tmp/php"$version"_extensions
  mkdir -p /tmp/extdisabled/"$version"
  echo '' | sudo tee /tmp/extdisabled/"$version"/"$extension" >/dev/null 2>&1
}

# Function to get extension name from brew formula.
get_extension_from_formula() {
  local formula=$1
  local extension
  extension=$(grep -E "^$formula=" "$src"/configs/brew_extensions | cut -d '=' -f 2)
  [[ -z "$extension" ]] && extension="$(echo "$formula" | sed -E "s/pecl_|php|[0-9]//g")"
  echo "$extension"
}

# Function to get renamed formula.
get_renamed_formula() {
  local formula=$1
  formula_renames_json="$tap_dir/$ext_tap/formula_renames.json"
  if [ -e "$formula_renames_json" ] && grep -q "$formula@$version\":" "$formula_renames_json"; then
    grep "$formula@$version\":" "$formula_renames_json" | cut -d ':' -f 2 | tr -d ' ",' | cut -d '@' -f 1
  else
    echo "$formula"
  fi
}

# Function to copy extension binaries to the extension directory.
copy_brew_extensions() {
  local formula=$1
  formula_file="$tap_dir/$ext_tap/Formula/$formula@$version.rb"
  deps="$(grep -Eo 'depends_on "shivammathur[^"]+' "$formula_file" | cut -d '/' -f 3 | tr '\n' ' ')"
  IFS=' ' read -r -a deps <<< "$formula@$version $deps"
  for dependency in "${deps[@]}"; do
    extension_file="${brew_prefix:?}/opt/$dependency/$(get_extension_from_formula "${dependency%@*}").so"
    [ -e "$extension_file" ] && sudo cp "$extension_file" "$ext_dir"
  done
  if [ -d "$brew_prefix"/Cellar/"$formula"@"$version" ]; then
    sudo find -- "$brew_prefix"/Cellar/"$formula"@"$version" -name "*.dylib" -exec cp {} "$ext_dir" \;
  fi
}

# Function to install a php extension from shivammathur/extensions tap.
add_brew_extension() {
  formula=$1
  prefix=$2
  extension="$(get_extension_from_formula "$formula")"
  enable_extension "$extension" "$prefix"
  if check_extension "$extension"; then
    add_log "${tick:?}" "$extension" "Enabled"
  else
    add_brew_tap "$php_tap"
    add_brew_tap "$ext_tap"
    formula="$(get_renamed_formula "$formula")"
    update_dependencies >/dev/null 2>&1
    handle_dependency_extensions "$formula" "$extension" >/dev/null 2>&1
    (
      safe_brew install --skip-link "${brew_opts[@]}" "$ext_tap/$formula@$version" >/dev/null 2>&1 &&
      brew link --overwrite --force "$formula@$version" >/dev/null 2>&1 &&
      copy_brew_extensions "$formula"
    ) || pecl_install "$extension" >/dev/null 2>&1
    add_extension_log "$extension" "Installed and enabled"
  fi
}

# Function to patch the abstract file in the extensions tap.
patch_abstract_file() {
    abstract_path="$tap_dir"/"$ext_tap"/Abstract/abstract-php-extension.rb
    if [[ -e "$abstract_path" && ! -e /tmp/abstract_patch ]]; then
        echo '' | sudo tee /tmp/abstract_patch >/dev/null 2>&1
        sudo sed -i '' -e "s|php@#{\(.*\)}|php@#{\1}$suffix|g" -e "s|php_version /|\"#{php_version}$suffix\" /|g" "$abstract_path"
    fi
}

# Helper function to add an extension.
add_extension_helper() {
  local extension=$1
  prefix=$2
  if [[ "$version" =~ ${old_versions:?} ]] && [ "$extension" = "imagick" ]; then
    run_script "php5-darwin" "${version/./}" "$extension" >/dev/null 2>&1
  else
    pecl_install "$extension" >/dev/null 2>&1 &&
    if [[ "$version" =~ ${old_versions:?} ]]; then echo "$prefix=$ext_dir/$extension.so" >>"$ini_file"; fi
  fi
  add_extension_log "$extension" "Installed and enabled"
}

# Function to handle request to add phpize and php-config.
add_devtools() {
  tool=$1
  add_log "${tick:?}" "$tool" "Added $tool $semver"
}

# Function to handle request to add PECL.
add_pecl() {
  enable_extension xml extension >/dev/null 2>&1
  configure_pecl >/dev/null 2>&1
  pear_version=$(get_tool_version "pecl" "version")
  add_log "${tick:?}" "PECL" "Found PECL $pear_version"
}

# Link opcache extension to extensions directory.
link_opcache() {
  opcache_ini="$brew_prefix"/etc/php/"$version"/conf.d/ext-opcache.ini
  if [ -e "$opcache_ini" ]; then
    opcache_ext=$(grep -Eo "zend_extension.*opcache.*\.so" "$opcache_ini" | cut -d '"' -f 2)
    sudo ln -sf "$opcache_ext" "$ext_dir"
  fi
}

# Patch brew to overwrite packages.
patch_brew() {
  formula_installer="${brew_repo:?}"/Library/Homebrew/formula_installer.rb
  code=" keg.link\(verbose: verbose\?"
  sudo sed -Ei '' "s/$code.*/$code, overwrite: true\)/" "$formula_installer"
  # shellcheck disable=SC2064
  trap "sudo sed -Ei '' 's/$code.*/$code, overwrite: overwrite?\)/' $formula_installer" exit
}

# Function to update dependencies.
update_dependencies() {
  patch_brew
  if ! [ -e /tmp/update_dependencies ]; then
    for repo in "$brew_repo" "${core_repo:?}"; do
      if [ -e "$repo" ]; then
        git_retry -C "$repo" fetch origin main && git -C "$repo" reset --hard origin/main
      fi
    done
    echo '' | sudo tee /tmp/update_dependencies >/dev/null 2>&1
  fi
}

# Function to get PHP version if it is already installed using Homebrew.
get_brewed_php() {
  cellar="$brew_prefix"/Cellar
  php_cellar="$cellar"/php
  if [ -d "$cellar" ] && ! [[ "$(find "$cellar" -maxdepth 1 -name "php@$version*" | wc -l 2>/dev/null)" -eq 0 ]]; then
    php_semver
  elif [ -d "$php_cellar" ] && ! [[ "$(find "$php_cellar" -maxdepth 1 -name "$version*" | wc -l 2>/dev/null)" -eq 0 ]]; then
    php_semver
  else
    echo 'false';
  fi
}

# Function to setup PHP 5.6 and newer using Homebrew.
add_php() {
  action=$1
  existing_version=$2
  suffix="$(get_php_formula_suffix)"
  php_keg="php@$version$suffix"
  php_formula="shivammathur/php/$php_keg"
  if [[ "$existing_version" = "false" || -n "$suffix" || "$action" = "upgrade" ]]; then
    update_dependencies
    add_brew_tap "$php_tap"
  fi
  if [[ "$existing_version" != "false" && -z "$suffix" ]]; then
    if [ "$action" = "upgrade" ]; then
      safe_brew install --only-dependencies "$php_formula"
      safe_brew upgrade -f --overwrite "$php_formula"
    else
      brew unlink "$php_keg"
    fi
  else
    safe_brew install --only-dependencies "$php_formula"
    safe_brew install --skip-link -f --overwrite "$php_formula" 2>/dev/null || safe_brew upgrade -f --overwrite "$php_formula"
  fi
  brew link --force --overwrite "$php_keg" || (sudo chown -R "$(id -un)":"$(id -gn)" "$brew_prefix" && brew link --force --overwrite "$php_keg")
}

# Function to get formula suffix
get_php_formula_suffix() {
  local suffix
  [ "${debug:?}" = "debug" ] && suffix="-debug"
  [ "${ts:?}" = "zts" ] && suffix="$suffix-zts"
  echo "$suffix"
}

# Function to get extra version.
php_extra_version() {
  php_formula_file="$tap_dir"/"$php_tap"/Formula/php@"$version".rb
  if [ -e "$php_formula_file" ] && ! grep -q "deprecate!" "$php_formula_file" && grep -Eq "archive/[0-9a-zA-Z]+" "$php_formula_file"; then
    echo " ($(grep -Eo "archive/[0-9a-zA-Z]+" "$php_formula_file" | cut -d'/' -f 2))"
  fi
}

# Function to set php.ini
add_php_config() {
  if ! [ -e "$ini_dir"/php.ini-development ]; then
    sudo cp "$ini_dir"/php.ini "$ini_dir"/php.ini-development
  fi
  if [[ "$ini" = "production" || "$ini" = "development" ]]; then
    sudo cp "$ini_dir"/php.ini-"$ini" "$ini_dir"/php.ini
  elif [ "$ini" = "none" ]; then
    echo '' | sudo tee "${ini_file[@]}" >/dev/null 2>&1
  fi
}

# Function to get scan directory.
get_scan_dir() {
  if [[ "$version" =~ ${old_versions:?} ]]; then
    php --ini | grep additional | sed -e "s|.*: s*||"
  else
    echo "$ini_dir"/conf.d
  fi
}

# Function to handle self-hosted runner setup.
self_hosted_helper() {
  sudo mkdir -p /opt/hostedtoolcache >/dev/null 2>&1 || true
}

# Function to Setup PHP.
setup_php() {
  step_log "Setup PHP"
  php_config="$(command -v php-config 2>/dev/null)"
  update=true
  check_pre_installed
  existing_version=$(get_brewed_php)
  status="Found"
  if [[ "$version" =~ ${old_versions:?} ]]; then
    run_script "php5-darwin" "${version/./}" >/dev/null 2>&1
    status="Installed"
  elif [ "${existing_version:0:3}" != "$version" ]; then
    add_php "install" "$existing_version" >/dev/null 2>&1
    status="Installed"
  elif [[ "${existing_version:0:3}" = "$version" && "${update:?}" = "true" ]]; then
    brew_php_version="$(brew info --json "php@$version" 2>/dev/null | jq -r '.[].versions.stable')"
    if [ "$brew_php_version" != "$existing_version" ]; then
      add_php "upgrade" "$existing_version" >/dev/null 2>&1
      status="Upgraded"
    fi
  fi
  php_config="$(command -v php-config)"
  ext_dir="$(sed -n "s/.*extension_dir=['\"]\(.*\)['\"].*/\1/p" "$php_config")"
  ini_dir="$(php_ini_path)"
  scan_dir="$(get_scan_dir)"
  ini_file="$ini_dir"/php.ini
  sudo mkdir -m 777 -p "$ext_dir" "$HOME/.composer"
  sudo chmod 777 "$ini_file" "${tool_path_dir:?}"
  semver="$(php_semver)"
  extra_version="$(php_extra_version)"
  configure_php
  link_opcache
  set_output "php-version" "$semver"
  if [ "${semver%.*}" != "$version" ]; then
    add_log "${cross:?}" "PHP" "Could not setup PHP $version"
    exit 1
  fi

  sudo cp "$src"/configs/pm/*.json "$RUNNER_TOOL_CACHE/"
  add_log "$tick" "PHP" "$status PHP $semver$extra_version"
}

# Variables
version=${1:-'8.5'}
ini=${2:-'production'}
src=${0%/*}/..
php_formula=shivammathur/php/php@"$version"
scripts="$src"/scripts
ext_tap=shivammathur/homebrew-extensions
php_tap=shivammathur/homebrew-php
export HOMEBREW_CHANGE_ARCH_TO_ARM=1
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_ENV_HINTS=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_FROM_API=1

# shellcheck source=.
. "${scripts:?}"/unix.sh
. "${scripts:?}"/tools/brew.sh
. "${scripts:?}"/tools/retry.sh
. "${scripts:?}"/tools/add_tools.sh
. "${scripts:?}"/extensions/source.sh
. "${scripts:?}"/extensions/add_extensions.sh
configure_brew
read_env
self_hosted_setup
setup_php
