#!/usr/bin/env bash
set -euo pipefail
source "$SHELLOPS_DIR/.envrc"
import "$SHELLOPS_DIR/lib/homebrew/api.sh"
import "$SHELLOPS_DIR/lib/manifest.api.sh"

USAGE="$(cat <<EOF
Generates a Homebrew formula and pushes it to a tap repository.

When --tap-repo is provided, handles the full cycle: clone, generate
formula, commit, and push. When --dir is provided instead, only writes
the formula file (caller handles git operations).

Flags override manifest.json values. If --name, --version, --description,
--homepage, or --bin are omitted, they fall back to the project manifest.

Usage: action homebrew update-tap [options]

Options:
  --tap-repo <url>       Git clone URL of the tap repo (includes credentials if needed).
                         Mutually exclusive with --dir.
  --dir <path>           Path to an already-cloned tap repository.
                         Mutually exclusive with --tap-repo.
  --asset-url <url>      Base URL where release tarballs are hosted (required).
  --asset-dir <dir>      Local directory containing tarballs for SHA256 computation (required).
  --name <name>          Formula/binary name. Defaults to manifest command-name.
  --version <version>    Release version. Defaults to manifest stable version.
  --description <text>   One-line description. Defaults to manifest description.
  --homepage <url>       Project homepage URL. Defaults to GitHub repo URL from manifest.
  --license <spdx>       SPDX license identifier. Defaults to MIT.
  --bin <name>           Binary filename to install. Defaults to manifest command-name.
  -h, --help             Show this help text.
EOF
)"

function main() {
  local args
  args="$(parse_args "$@")"
  args="$(apply_manifest_defaults "$args")"
  validate_args "$args"

  local formula_rb
  formula_rb="$(homebrew_generate_formula \
    "$args" \
    "$(jq_get "$args" '.asset_url')" \
    "$(jq_get "$args" '.asset_dir')" \
  )"

  local tap_repo name version
  tap_repo="$(jq_get "$args" '.tap_repo')"
  name="$(jq_get "$args" '.name')"
  version="$(jq_get "$args" '.version')"

  if jq_defined "$tap_repo"; then
    homebrew_update_tap "$tap_repo" "$formula_rb" "$name" "$version"
  else
    local dir
    dir="$(jq_get "$args" '.dir')"
    mkdir -p "${dir}/Formula"
    echo "$formula_rb" > "${dir}/Formula/${name}.rb"
    log "wrote Formula/${name}.rb"
  fi
}

function apply_manifest_defaults() {
  local args="$1"

  jq_defined "$(jq_get "$args" '.name')" || \
    args="$(jq_set "$args" '.name' "$(manifest_get command_name 2>/dev/null || true)")"

  jq_defined "$(jq_get "$args" '.version')" || \
    args="$(jq_set "$args" '.version' "$(manifest_get stable 2>/dev/null || true)")"

  jq_defined "$(jq_get "$args" '.description')" || \
    args="$(jq_set "$args" '.description' "$(manifest_get description 2>/dev/null || true)")"

  jq_defined "$(jq_get "$args" '.bin')" || \
    args="$(jq_set "$args" '.bin' "$(manifest_get command_name 2>/dev/null || true)")"

  if ! jq_defined "$(jq_get "$args" '.homepage')"; then
    local org repo
    org="$(manifest_get org 2>/dev/null || true)"
    repo="$(manifest_get repo 2>/dev/null || true)"
    [[ -n "$org" && -n "$repo" ]] && \
      args="$(jq_set "$args" '.homepage' "https://github.com/${org}/${repo}")"
  fi

  echo "$args"
}

function validate_args() {
  local args="$1"
  local missing=""

  local tap_repo dir
  tap_repo="$(jq_get "$args" '.tap_repo')"
  dir="$(jq_get "$args" '.dir')"

  if jq_defined "$tap_repo" && jq_defined "$dir"; then
    error "--tap-repo and --dir are mutually exclusive"
    exit 1
  fi

  ! jq_defined "$tap_repo" && ! jq_defined "$dir"       && missing="${missing}  --tap-repo or --dir\n"
  jq_defined "$(jq_get "$args" '.asset_url')" || missing="${missing}  --asset-url\n"
  jq_defined "$(jq_get "$args" '.asset_dir')" || missing="${missing}  --asset-dir\n"
  jq_defined "$(jq_get "$args" '.name')"      || missing="${missing}  --name (not in manifest either)\n"
  jq_defined "$(jq_get "$args" '.version')"   || missing="${missing}  --version (not in manifest either)\n"

  if [[ -n "$missing" ]]; then
    error "missing required options:"
    echo -e "$missing" >&2
    log "$USAGE"
    exit 1
  fi
}

function parse_args() {
  local args
  args="$(jq_obj '.license' 'MIT')"

  while [[ $# -gt 0 ]]; do
    case "$1" in
      -h|--help)      log "$USAGE"; exit 0 ;;
      --tap-repo)     args="$(jq_set "$args" '.tap_repo' "$2")"; shift ;;
      --dir)          args="$(jq_set "$args" '.dir' "$2")"; shift ;;
      --name)         args="$(jq_set "$args" '.name' "$2")"; shift ;;
      --version)      args="$(jq_set "$args" '.version' "$2")"; shift ;;
      --asset-url)    args="$(jq_set "$args" '.asset_url' "$2")"; shift ;;
      --asset-dir)    args="$(jq_set "$args" '.asset_dir' "$2")"; shift ;;
      --description)  args="$(jq_set "$args" '.description' "$2")"; shift ;;
      --homepage)     args="$(jq_set "$args" '.homepage' "$2")"; shift ;;
      --license)      args="$(jq_set "$args" '.license' "$2")"; shift ;;
      --bin)          args="$(jq_set "$args" '.bin' "$2")"; shift ;;
      -*)
        error "Unknown option: $1"
        exit 1
        ;;
    esac
    shift
  done

  echo "$args"
}

if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
  main "$@"
fi
