#!/usr/bin/env bash

import "$SHELLOPS_DIR/lib/tarball/api.sh"
import "$SHELLOPS_DIR/lib/http.api.sh"

: <<'DOC'
Homebrew formula generation and tap management.

Generates Ruby formula files for binary taps and handles
the clone/update/commit/push cycle for tap repositories.
DOC

HOMEBREW_METADATA_SCHEMA="${SHELLOPS_DIR}/lib/homebrew/formula_metadata.schema.json"

: <<'DOC'
Builds and validates a formula metadata JSON object.

Required:
  name     - formula/binary name
  version  - release version

Optional (pass empty string to omit):
  description - one-line description
  homepage    - project URL
  license     - SPDX identifier (defaults to MIT)
  bin         - binary filename if different from name

  homebrew_build_metadata "insights" "1.2.0" "Knowledge management" "https://..." "MIT" ""
DOC
function homebrew_build_metadata() {
  local name="$1" version="$2"
  local description="${3:-}" homepage="${4:-}" license="${5:-MIT}" bin_name="${6:-}"

  local metadata
  metadata="$(jq_obj '.name' "$name" '.version' "$version" '.license' "$license")"

  [[ -n "$description" ]] && metadata="$(jq_set "$metadata" '.description' "$description")"
  [[ -n "$homepage" ]]    && metadata="$(jq_set "$metadata" '.homepage' "$homepage")"
  [[ -n "$bin_name" ]]    && metadata="$(jq_set "$metadata" '.bin' "$bin_name")"

  if ! jq_validate "$metadata" "$HOMEBREW_METADATA_SCHEMA"; then
    return 1
  fi

  echo "$metadata"
}

: <<'DOC'
Generates a Homebrew formula (.rb) for a pre-built binary distributed
across macOS and Linux for both x86_64 and aarch64.

Computes SHA256 hashes from local tarballs in asset_dir.

Parameters:
  metadata  JSON object:
              name        - formula/binary name (e.g. "insights")
              version     - release version (e.g. "1.2.0")
              description - one-line description
              homepage    - project URL
              license     - SPDX identifier (e.g. "MIT")
              bin         - binary filename to install (defaults to name)
  asset_url - base URL where release tarballs are hosted
  asset_dir - local directory containing the tarballs (for SHA256 computation)

Writes the formula to stdout.

  homebrew_generate_formula "$metadata" "https://example.com/releases/v1.2.0" "./dist"
DOC
function homebrew_generate_formula() {
  local metadata="$1" asset_url="$2" asset_dir="$3"

  local name version description homepage license bin_name
  name="$(jq_get "$metadata" '.name')"
  version="$(jq_get "$metadata" '.version')"
  description="$(jq_get "$metadata" '.description')"
  homepage="$(jq_get "$metadata" '.homepage')"
  license="$(jq_get "$metadata" '.license')"
  bin_name="$(jq_get "$metadata" '.bin' "$name")"

  local class_name
  class_name="$(__homebrew__ruby_class_name "$name")"

  local darwin_x86_sha darwin_arm_sha linux_x86_sha linux_arm_sha
  darwin_x86_sha="$(__homebrew__sha256_for "$name" "$version" "x86_64-apple-darwin" "$asset_dir")"
  darwin_arm_sha="$(__homebrew__sha256_for "$name" "$version" "aarch64-apple-darwin" "$asset_dir")"
  linux_x86_sha="$(__homebrew__sha256_for "$name" "$version" "x86_64-unknown-linux-gnu" "$asset_dir")"
  linux_arm_sha="$(__homebrew__sha256_for "$name" "$version" "aarch64-unknown-linux-gnu" "$asset_dir")"

  local darwin_x86_url darwin_arm_url linux_x86_url linux_arm_url
  darwin_x86_url="${asset_url}/$(tarball_artifact_name "$name" "$version" "x86_64-apple-darwin")"
  darwin_arm_url="${asset_url}/$(tarball_artifact_name "$name" "$version" "aarch64-apple-darwin")"
  linux_x86_url="${asset_url}/$(tarball_artifact_name "$name" "$version" "x86_64-unknown-linux-gnu")"
  linux_arm_url="${asset_url}/$(tarball_artifact_name "$name" "$version" "aarch64-unknown-linux-gnu")"

  local template="${SHELLOPS_DIR}/lib/homebrew/formula.rb.tmpl"

  sed \
    -e "s|{{class_name}}|${class_name}|g" \
    -e "s|{{description}}|${description}|g" \
    -e "s|{{homepage}}|${homepage}|g" \
    -e "s|{{version}}|${version}|g" \
    -e "s|{{license}}|${license}|g" \
    -e "s|{{bin_name}}|${bin_name}|g" \
    -e "s|{{darwin_arm_url}}|${darwin_arm_url}|g" \
    -e "s|{{darwin_arm_sha}}|${darwin_arm_sha}|g" \
    -e "s|{{darwin_x86_url}}|${darwin_x86_url}|g" \
    -e "s|{{darwin_x86_sha}}|${darwin_x86_sha}|g" \
    -e "s|{{linux_arm_url}}|${linux_arm_url}|g" \
    -e "s|{{linux_arm_sha}}|${linux_arm_sha}|g" \
    -e "s|{{linux_x86_url}}|${linux_x86_url}|g" \
    -e "s|{{linux_x86_sha}}|${linux_x86_sha}|g" \
    "$template"
}

function __homebrew__sha256_for() {
  local name="$1" version="$2" triple="$3" asset_dir="$4"
  local filename
  filename="$(tarball_artifact_name "$name" "$version" "$triple")"
  local filepath="${asset_dir}/${filename}"

  if [[ ! -f "$filepath" ]]; then
    error "tarball not found: ${filepath}"
    return 1
  fi

  sha256sum "$filepath" | cut -d' ' -f1
}

function __homebrew__ruby_class_name() {
  local name="$1"
  local result="" capitalize_next="true"
  local i char

  for (( i = 0; i < ${#name}; i++ )); do
    char="${name:$i:1}"
    if [[ "$char" == "-" || "$char" == "_" ]]; then
      capitalize_next="true"
      continue
    fi

    if [[ "$capitalize_next" == "true" ]]; then
      result+="$(echo "$char" | tr '[:lower:]' '[:upper:]')"
      capitalize_next="false"
    else
      result+="$char"
    fi
  done

  echo "$result"
}

: <<'DOC'
Clones or updates a tap repository, writes a formula, commits, and pushes.

Parameters:
  tap_url    - git clone URL of the tap repo
  formula_rb - the formula content (string, typically from homebrew_generate_formula)
  name       - formula name (used for the filename and commit message)
  version    - version string (used in the commit message)
  options    - optional JSON object:
                 branch     - branch to push to (default: "main")
                 dir        - working directory for the clone (default: mktemp -d)
                 git_name   - committer name (default: "Blizz")
                 git_email  - committer email (default: "blizz@kernelle-soft.com")

  homebrew_update_tap "$tap_url" "$formula_rb" "insights" "1.2.0"
DOC
function homebrew_update_tap() {
  local tap_url="$1" formula_rb="$2" name="$3" version="$4"
  local options="${5:-{\}}"

  local branch workdir git_name git_email
  branch="$(jq_get "$options" '.branch' 'main')"
  workdir="$(jq_get "$options" '.dir' '')"
  git_name="$(jq_get "$options" '.git_name' 'Blizz')"
  git_email="$(jq_get "$options" '.git_email' 'blizz@kernelle-soft.com')"

  if [[ -z "$workdir" ]]; then
    workdir="$(mktemp -d)"
  fi

  __homebrew__clone "$tap_url" "$workdir"
  __homebrew__checkout "$workdir" "$branch"
  __homebrew__configure_identity "$workdir" "$git_name" "$git_email"
  __homebrew__write_formula "$workdir" "$name" "$formula_rb"
  __homebrew__commit_and_push "$workdir" "$name" "$version" "$branch"
}

function __homebrew__clone() {
  local tap_url="$1" workdir="$2"

  if [[ -d "$workdir/.git" ]]; then
    log "updating tap at ${workdir}"
    git -C "$workdir" fetch origin
  else
    log "cloning tap from ${tap_url}"
    git clone "$tap_url" "$workdir"
  fi
}

function __homebrew__checkout() {
  local workdir="$1" branch="$2"
  git -C "$workdir" checkout "$branch"
  git -C "$workdir" reset --hard "origin/${branch}"
}

function __homebrew__configure_identity() {
  local workdir="$1" name="$2" email="$3"
  git -C "$workdir" config user.name "$name"
  git -C "$workdir" config user.email "$email"
}

function __homebrew__write_formula() {
  local workdir="$1" name="$2" formula_rb="$3"
  local formula_dir="${workdir}/Formula"

  mkdir -p "$formula_dir"
  echo "$formula_rb" > "${formula_dir}/${name}.rb"
  log "wrote Formula/${name}.rb"
}

function __homebrew__commit_and_push() {
  local workdir="$1" name="$2" version="$3" branch="$4"

  git -C "$workdir" add "Formula/${name}.rb"

  if git -C "$workdir" diff --cached --quiet; then
    log "no changes to Formula/${name}.rb"
    return 0
  fi

  git -C "$workdir" commit -m "${name} ${version}"
  git -C "$workdir" push --force-with-lease origin "$branch"
  log "pushed ${name} ${version} to tap"
}
