#!/usr/bin/env bash
set -Eeuo pipefail

PROGRAM="$(basename "$0")"
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CONFIG_FILE="${ALIYUN_OSS_PROJECT_CONFIG:-${REPO_ROOT}/config/aliyun-oss.env}"
LOCAL_CONFIG_FILE="${REPO_ROOT}/config/aliyun-oss.local.env"

usage() {
  cat <<'EOF'
Usage:
  bash scripts/aliyun_oss_project_assets.sh check
  bash scripts/aliyun_oss_project_assets.sh list [remote-prefix]
  bash scripts/aliyun_oss_project_assets.sh list-spreadsheets
  bash scripts/aliyun_oss_project_assets.sh pull [remote-prefix] [local-dir]
  bash scripts/aliyun_oss_project_assets.sh pull-spreadsheets [local-dir]
  bash scripts/aliyun_oss_project_assets.sh push-local [local-dir] [remote-prefix]
  bash scripts/aliyun_oss_project_assets.sh push-spreadsheets [--dry-run]
  bash scripts/aliyun_oss_project_assets.sh push-html-public [--dry-run]
  bash scripts/aliyun_oss_project_assets.sh list-html-public
  bash scripts/aliyun_oss_project_assets.sh manifest
  bash scripts/aliyun_oss_project_assets.sh html-manifest

Purpose:
  Connect this project to Alibaba Cloud OSS without committing credentials.
  Project defaults live in config/aliyun-oss.env. Per-machine overrides may live
  in ignored config/aliyun-oss.local.env.
EOF
}

info() {
  printf '[%s] %s\n' "$PROGRAM" "$*"
}

die() {
  printf '[%s] ERROR: %s\n' "$PROGRAM" "$*" >&2
  exit 1
}

load_env_file() {
  local file="$1"
  [ -f "$file" ] || return 0
  # shellcheck disable=SC1090
  source "$file"
}

require_tooling() {
  command -v aliyun >/dev/null 2>&1 || die "Alibaba Cloud CLI 'aliyun' is not installed."
  aliyun ossutil version >/dev/null 2>&1 || die "aliyun ossutil is not available. Upgrade Alibaba Cloud CLI."
}

load_config() {
  load_env_file "$CONFIG_FILE"
  load_env_file "$LOCAL_CONFIG_FILE"

  : "${ALIYUN_OSS_PROFILE:=}"
  : "${ALIYUN_OSS_REGION:=cn-beijing}"
  : "${ALIYUN_OSS_ENDPOINT:=https://oss-cn-beijing.aliyuncs.com}"
  : "${ALIYUN_OSS_BUCKET:=}"
  : "${ALIYUN_OSS_PREFIX:=bid-analysis-methodology}"
  : "${ALIYUN_OSS_LOCAL_DIR:=oss}"
  : "${ALIYUN_OSS_SPREADSHEET_PREFIX:=${ALIYUN_OSS_PREFIX}/spreadsheets}"
  : "${ALIYUN_OSS_PUBLIC_BUCKET:=}"
  : "${ALIYUN_OSS_PUBLIC_PREFIX:=public/${ALIYUN_OSS_PREFIX}}"
  : "${ALIYUN_OSS_PUBLIC_BASE_URL:=}"
  : "${ALIYUN_OSS_HTML_PUBLIC_PREFIX:=$ALIYUN_OSS_PUBLIC_PREFIX}"

  [ -n "$ALIYUN_OSS_BUCKET" ] || die "ALIYUN_OSS_BUCKET is not set."
}

oss_uri() {
  local prefix="${1:-$ALIYUN_OSS_PREFIX}"
  prefix="${prefix#/}"
  printf 'oss://%s/%s' "$ALIYUN_OSS_BUCKET" "$prefix"
}

public_oss_uri() {
  [ -n "$ALIYUN_OSS_PUBLIC_BUCKET" ] || die "ALIYUN_OSS_PUBLIC_BUCKET is not set."
  local prefix="${1:-$ALIYUN_OSS_PUBLIC_PREFIX}"
  prefix="${prefix#/}"
  printf 'oss://%s/%s' "$ALIYUN_OSS_PUBLIC_BUCKET" "$prefix"
}

run_ossutil() {
  local extra_args=(--region "$ALIYUN_OSS_REGION" --endpoint "$ALIYUN_OSS_ENDPOINT")
  if [ -n "$ALIYUN_OSS_PROFILE" ]; then
    extra_args+=(--profile "$ALIYUN_OSS_PROFILE")
  fi
  aliyun ossutil "$@" "${extra_args[@]}"
}

cmd_check() {
  require_tooling
  load_config
  info "Repository: $REPO_ROOT"
  info "Config: $CONFIG_FILE"
  [ ! -f "$LOCAL_CONFIG_FILE" ] || info "Local override: $LOCAL_CONFIG_FILE"
  info "Profile: ${ALIYUN_OSS_PROFILE:-default}"
  info "Region: $ALIYUN_OSS_REGION"
  info "Endpoint: $ALIYUN_OSS_ENDPOINT"
  info "Bucket: $ALIYUN_OSS_BUCKET"
  info "Project prefix: $ALIYUN_OSS_PREFIX"
  info "Local dir: $ALIYUN_OSS_LOCAL_DIR"
  info "Public bucket: ${ALIYUN_OSS_PUBLIC_BUCKET:-unset}"
  info "Public prefix: $ALIYUN_OSS_PUBLIC_PREFIX"
  info "Public base URL: ${ALIYUN_OSS_PUBLIC_BASE_URL:-unset}"
  run_ossutil stat "oss://${ALIYUN_OSS_BUCKET}"
}

cmd_list() {
  require_tooling
  load_config
  local prefix="${1:-$ALIYUN_OSS_PREFIX}"
  run_ossutil ls "$(oss_uri "$prefix")" --limited-num 100
}

cmd_list_spreadsheets() {
  require_tooling
  load_config
  run_ossutil ls "$(oss_uri "$ALIYUN_OSS_SPREADSHEET_PREFIX")" --limited-num 200
}

cmd_pull() {
  require_tooling
  load_config
  local prefix="${1:-$ALIYUN_OSS_PREFIX}"
  local local_dir="${2:-$ALIYUN_OSS_LOCAL_DIR}"
  mkdir -p "$REPO_ROOT/$local_dir"
  run_ossutil sync "$(oss_uri "$prefix")" "$REPO_ROOT/$local_dir"
}

cmd_pull_spreadsheets() {
  require_tooling
  load_config
  local local_dir="${1:-$ALIYUN_OSS_LOCAL_DIR/spreadsheets}"
  mkdir -p "$REPO_ROOT/$local_dir"
  run_ossutil sync "$(oss_uri "$ALIYUN_OSS_SPREADSHEET_PREFIX")" "$REPO_ROOT/$local_dir"
}

cmd_push_local() {
  require_tooling
  load_config
  local local_dir="${1:-$ALIYUN_OSS_LOCAL_DIR}"
  local prefix="${2:-$ALIYUN_OSS_PREFIX}"
  [ -d "$REPO_ROOT/$local_dir" ] || die "Local directory does not exist: $local_dir"
  run_ossutil sync "$REPO_ROOT/$local_dir" "$(oss_uri "$prefix")"
}

cmd_push_spreadsheets() {
  require_tooling
  load_config
  local dry_run="${1:-}"
  local maybe_dry_run=()
  if [ "$dry_run" = "--dry-run" ]; then
    maybe_dry_run=(--dry-run)
  elif [ -n "$dry_run" ]; then
    die "Unexpected argument: $dry_run"
  fi

  if [ "$dry_run" = "--dry-run" ]; then
    run_ossutil sync "$REPO_ROOT/docs" "$(oss_uri "$ALIYUN_OSS_SPREADSHEET_PREFIX/docs")" \
      --include '*.xlsx' --include '*.xls' --include '*.xlsm' --include '*.csv' -f "${maybe_dry_run[@]}"
    if [ -d "$REPO_ROOT/workflows" ]; then
      run_ossutil sync "$REPO_ROOT/workflows" "$(oss_uri "$ALIYUN_OSS_SPREADSHEET_PREFIX/workflows")" \
        --include '*.xlsx' --include '*.xls' --include '*.xlsm' --include '*.csv' -f "${maybe_dry_run[@]}"
    fi
  else
    run_ossutil sync "$REPO_ROOT/docs" "$(oss_uri "$ALIYUN_OSS_SPREADSHEET_PREFIX/docs")" \
      --include '*.xlsx' --include '*.xls' --include '*.xlsm' --include '*.csv' -f
    if [ -d "$REPO_ROOT/workflows" ]; then
      run_ossutil sync "$REPO_ROOT/workflows" "$(oss_uri "$ALIYUN_OSS_SPREADSHEET_PREFIX/workflows")" \
        --include '*.xlsx' --include '*.xls' --include '*.xlsm' --include '*.csv' -f
    fi
  fi
}

html_explanation_files() {
  cd "$REPO_ROOT"
  {
    find . -maxdepth 1 -type f -name '*.html' -print
    find workflows -type f -name '*.html' -print 2>/dev/null || true
    find docs/oss-assets docs/runs -type f -name '*.html' -print 2>/dev/null || true
    find docs -maxdepth 1 -type f -name '*.html' -print 2>/dev/null || true
    find skills -type f -name '*.html' -print 2>/dev/null || true
  } | sed 's#^\./##' | sort -u
}

cmd_push_html_public() {
  require_tooling
  load_config
  local dry_run="${1:-}"
  local files_list
  files_list="$(mktemp "${TMPDIR:-/tmp}/bid-oss-html-files.XXXXXX")"
  html_explanation_files > "$files_list"

  if [ "$dry_run" = "--dry-run" ]; then
    run_ossutil sync "$REPO_ROOT" "$(public_oss_uri "$ALIYUN_OSS_HTML_PUBLIC_PREFIX")" \
      --files-from "$files_list" --content-type 'text/html; charset=utf-8' -f --dry-run
  elif [ -n "$dry_run" ]; then
    rm -f "$files_list"
    die "Unexpected argument: $dry_run"
  else
    run_ossutil sync "$REPO_ROOT" "$(public_oss_uri "$ALIYUN_OSS_HTML_PUBLIC_PREFIX")" \
      --files-from "$files_list" --content-type 'text/html; charset=utf-8' -f
  fi
  rm -f "$files_list"
}

cmd_list_html_public() {
  require_tooling
  load_config
  run_ossutil ls "$(public_oss_uri "$ALIYUN_OSS_HTML_PUBLIC_PREFIX")" --include '*.html' --limited-num 200 -r
}

cmd_manifest() {
  load_config
  cd "$REPO_ROOT"
  find docs workflows -type f \( -iname '*.xlsx' -o -iname '*.xls' -o -iname '*.xlsm' -o -iname '*.csv' \) \
    -not -path '*/.DS_Store' \
    -print | sort | while IFS= read -r path; do
      local remote_prefix
      case "$path" in
        docs/*) remote_prefix="${ALIYUN_OSS_SPREADSHEET_PREFIX}/docs/${path#docs/}" ;;
        workflows/*) remote_prefix="${ALIYUN_OSS_SPREADSHEET_PREFIX}/workflows/${path#workflows/}" ;;
        *) remote_prefix="${ALIYUN_OSS_SPREADSHEET_PREFIX}/${path}" ;;
      esac
      printf '%s\t%s\t%s\n' "$path" "$(stat -f '%z' "$path")" "$(oss_uri "$remote_prefix")"
    done
}

cmd_html_manifest() {
  load_config
  cd "$REPO_ROOT"
  html_explanation_files | while IFS= read -r path; do
    [ -f "$path" ] || continue
    local remote_prefix url
    remote_prefix="${ALIYUN_OSS_HTML_PUBLIC_PREFIX}/${path}"
    if [ -n "$ALIYUN_OSS_PUBLIC_BASE_URL" ]; then
      url="${ALIYUN_OSS_PUBLIC_BASE_URL%/}/${path}"
    else
      url=""
    fi
    printf '%s\t%s\t%s\t%s\n' "$path" "$(stat -f '%z' "$path")" "$(public_oss_uri "$remote_prefix")" "$url"
  done
}

main() {
  local command="${1:-}"
  shift || true
  case "$command" in
    check) cmd_check "$@" ;;
    list) cmd_list "$@" ;;
    list-spreadsheets) cmd_list_spreadsheets "$@" ;;
    pull) cmd_pull "$@" ;;
    pull-spreadsheets) cmd_pull_spreadsheets "$@" ;;
    push-local) cmd_push_local "$@" ;;
    push-spreadsheets) cmd_push_spreadsheets "$@" ;;
    push-html-public) cmd_push_html_public "$@" ;;
    list-html-public) cmd_list_html_public "$@" ;;
    manifest) cmd_manifest "$@" ;;
    html-manifest) cmd_html_manifest "$@" ;;
    -h|--help|help|'') usage ;;
    *) usage >&2; die "Unknown command: $command" ;;
  esac
}

main "$@"
