#compdef ng

setopt localoptions extendedglob

if (( CURRENT == 2 )); then
  local -a cmds alias
  # Sample output (ng help):
  # Available Commands:
  #   add Adds support for an external library to your project.
  for line in ${(@f)"$(ng help 2>/dev/null | sed -n '/^  /p')"}; do
    if [[ "$line" =~ '^  ([^ ]+) \(([^)]+)\) (.*)$' ]]; then
      alias=(${match[1]} ${(s:, :)match[2]})
      cmds+=(${^alias}:"${match[3]//:/}")
    elif [[ "$line" =~ '^  ([^ ]+) (.*)$' ]]; then
      cmds+=("${match[1]}:${match[2]//:/}")
    fi
  done
  _describe commands cmds && return 0
elif (( CURRENT == 3 )); then
  local -a flags args
  local section description
  # Sample output (ng build --help):
  # --configuration (-c)
  #   One or more named builder configurations as a comma-separated list as specified in the "configurations" section of angular.json.
  #   The builder uses the named configurations to run the given target.
  #   For more information, see https://angular.io/guide/workspace-config#alternate-build-configurations.
  # Prefix --flags with literal \0, and split on that to get each flag section
  for section in ${(s:\0:)"$(ng ${words[2]} --help 2>/dev/null | sed -e '1,/^options/ d;s/^  --/\\0--/')"}; do
    # Split by newline and discard extra description lines (lines > 2)
    for args description in ${${(@f)section}[1,2]}; do
      args=(${(s: :)${${args%% #}## #}//[(),]/})
      description=${${description%% #}## #}
      flags+=(${^args}":$description")
    done
  done
  _describe flags flags

  case "$words[2]" in
  b|build|l|lint|t|test)
    # Sample output (ng config projects):
    # {
    #   "angular-project-1": {
    #     ...
    #   },
    #   "angular-project-2": {
    #     ...
    #   }
    # }
    # In abscence of a proper JSON parser, just grab the lines with
    # a 2-space indentation and only the stuff inside quotes
    local -a projects
    projects=(${(@f)"$(ng config projects 2>/dev/null | sed -n 's/^  "\([^"]\+\)".*$/\1/p')"})
    _describe projects projects
    ;;
  esac
fi