#!/usr/bin/env bash

set -euo pipefail

INCLUDE_PATTERNS=()
EXCLUDE_PATTERNS=()

usage() {
  cat <<'EOF'
Usage: ./package-release.sh [--include PATTERN]... [--exclude PATTERN]...

Examples:
  ./package-release.sh
  ./package-release.sh --include 'inc/*' --exclude '*.md'
EOF
}

while (($# > 0)); do
  case "$1" in
    --include)
      [[ $# -ge 2 ]] || { echo "Missing value for --include" >&2; exit 1; }
      INCLUDE_PATTERNS+=("$2")
      shift 2
      ;;
    --exclude)
      [[ $# -ge 2 ]] || { echo "Missing value for --exclude" >&2; exit 1; }
      EXCLUDE_PATTERNS+=("$2")
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage >&2
      exit 1
      ;;
  esac
done

get_stable_tag() {
  local readme
  readme=$(<"./README.txt")

  if [[ $readme =~ Stable[[:space:]]tag:[[:space:]]*([[:alnum:]_.-]+) ]]; then
    printf '%s\n' "${BASH_REMATCH[1]}"
    return 0
  fi

  echo "Stable tag not found in README.txt" >&2
  exit 1
}

get_gitignore_patterns() {
  local line

  [[ -f .gitignore ]] || return 0

  while IFS= read -r line || [[ -n $line ]]; do
    [[ -z $line ]] && continue
    [[ $line == \#* ]] && continue
    printf '%s\n' "$line"
  done < .gitignore
}

match_pattern() {
  local rel=$1
  local pattern=$2

  [[ -z $pattern ]] && return 1

  if [[ $pattern == '^'* || $pattern == *'$' || $pattern == *'+' || $pattern == *'|' ]]; then
    [[ $rel =~ $pattern ]]
    return
  fi

  if [[ $rel == $pattern || $rel == $pattern/* || $rel == */$pattern || $rel == */$pattern/* ]]; then
    return 0
  fi

  [[ $rel == $pattern ]]
}

should_skip_folder() {
  local rel=$1
  local folder

  for folder in node_modules vendor languages; do
    if [[ $rel == "$folder"/* || $rel == */"$folder"/* ]]; then
      return 0
    fi
  done

  return 1
}

should_include_file() {
  local rel=$1
  local pattern

  if ((${#INCLUDE_PATTERNS[@]} == 0)); then
    return 0
  fi

  for pattern in "${INCLUDE_PATTERNS[@]}"; do
    if match_pattern "$rel" "$pattern"; then
      return 0
    fi
  done

  return 1
}

should_exclude_file() {
  local rel=$1
  shift
  local pattern

  for pattern in "$@"; do
    if match_pattern "$rel" "$pattern"; then
      return 0
    fi
  done

  return 1
}

copy_project() {
  local dest=$1
  local is_trunk=$2
  shift 2
  local extra_exclude=("$@")
  local src_root dest_root total index rel target target_dir file
  local gitignore_patterns=()
  local all_excludes=()
  local files=()

  src_root=$(pwd)

  if [[ $dest = /* ]]; then
    dest_root=$dest
  else
    dest_root="$src_root/$dest"
  fi

  if [[ $is_trunk == "true" ]]; then
    while IFS= read -r line; do
      gitignore_patterns+=("$line")
    done < <(get_gitignore_patterns)
  fi

  all_excludes=("${gitignore_patterns[@]}" "${extra_exclude[@]}" "${EXCLUDE_PATTERNS[@]}")

  rm -rf "$dest_root"
  mkdir -p "$dest_root"

  while IFS= read -r -d '' file; do
    rel=${file#./}

    should_skip_folder "$rel" && continue

    if [[ $is_trunk == "true" && $rel == front/dist* ]]; then
      continue
    fi

    should_include_file "$rel" || continue
    should_exclude_file "$rel" "${all_excludes[@]}" && continue

    files+=("$rel")
  done < <(find . -type f -print0)

  total=${#files[@]}
  index=0

  for rel in "${files[@]}"; do
    index=$((index + 1))
    printf '\rCopying project files: %d/%d' "$index" "$total"

    target="$dest_root/$rel"
    target_dir=$(dirname "$target")
    mkdir -p "$target_dir"
    cp -f "$src_root/$rel" "$target"
  done

  if ((total > 0)); then
    printf '\n'
  fi
}

copy_assets() {
  local dest=$1
  local target

  [[ -d assets ]] || return 0

  target="$dest/assets"
  rm -rf "$target"
  cp -R assets "$target"
}

version=$(get_stable_tag)
main_folder="musahimoun-release-$version"
main_path="$PWD/$main_folder"

rm -rf "$main_path"
mkdir -p "$main_path"

trunk_exclude=(
  '.gitignore*'
  '.git*'
  'assets'
  '.vscode'
)

copy_project "$main_path/trunk" true "${trunk_exclude[@]}"

tag_exclude=(
  'package.json*'
  'package-lock.json*'
  'composer.json*'
  'composer.lock*'
  'package-plugin.ps1*'
  'package-release.ps1*'
  'package-release.sh*'
  'yarn.lock'
  'pnpm-lock.yaml'
  'Dockerfile*'
  'docker-compose*'
  '.env*'
  '.git*'
  '*.md'
  '*.MD'
  'node_modules*'
  'tests*'
  'test*'
  '.editorconfig'
  '.prettierrc.json'
  '.php-cs-fixer.php'
  '^\..+'
  'docs*'
  'front/src'
  'tsconfig.json*'
  'webpack.config*'
  '.vscode*'
  'languages'
  'musahimoun-release-*'
  'assets'
  '*.zip'
)

version_dest="$main_path/tags/$version"
copy_project "$version_dest" false "${tag_exclude[@]}"
copy_assets "$main_path"

echo "Packaging complete. Output:"
echo "  $main_folder/trunk/"
echo "  $main_folder/tags/$version/"
echo "  $main_folder/assets/"