#!/usr/bin/env bash
# =============================================================================
# awips_collect.sh — AWIPS2 GFE & D2D Selective / Full Tarball Collector
# =============================================================================
# Packages GFE Procedures, SmartTools, Utilities, TextUtilities, Configs, and
# D2D Procedures/Bundles/Menus from /awips2/edex/data/utility into a clean
# .tar.gz archive (stripping .pyc, .pyo, __pycache__, and .md5 files) for
# offline editing and testing.
# =============================================================================

set -euo pipefail

UTILITY_ROOT="/awips2/edex/data/utility"
OUTPUT_FILE="/home/john.peck/awips_export_$(date +%Y%m%d_%H%M%S).tar.gz"
LEVELS="site"
SITE_FILTER=""
USER_FILTER=""
NAME_MATCH=""
FULL_EXPORT=0

# Category flags
CAT_PROCEDURES=0
CAT_SMARTTOOLS=0
CAT_UTILITIES=0
CAT_TEXTUTILITIES=0
CAT_GFECONFIG=0
CAT_D2D_PROCEDURES=0
CAT_D2D_BUNDLES=0
CAT_MENUS=0
ANY_CAT_SET=0

usage() {
    cat <<'EOF'
Usage: awips_collect.sh [OPTIONS]

Category Selection (combine any; if none specified, collects all GFE + D2D categories):
  --procedures        GFE Procedures (cave_static/.../gfe/userPython/procedures)
  --smart-tools       GFE SmartTools (cave_static/.../gfe/userPython/smartTools)
  --utilities         GFE Utilities (cave_static/.../gfe/userPython/utilities)
  --text-utilities    GFE TextUtilities (cave_static/.../gfe/userPython/textUtilities)
  --gfe-config        GFE Configs & common_static GFE (gfeConfig + common_static/.../gfe)
  --gfe-all           All GFE categories above
  --d2d-procedures    D2D Procedures (cave_static/.../procedures)
  --d2d-bundles       D2D Bundles (cave_static/.../bundles)
  --menus             D2D & GFE Menus (cave_static/.../menus)
  --d2d-all           All D2D categories above
  --full              Full /awips2/edex/data/utility export (all categories)

Localization Level & Scope Filters:
  --levels <csv>      Comma-separated levels (default: configured,site,user)
                      Available: base,region,configured,site,user
  --include-base      Add 'base' to the localization levels
  --all-levels        Collect across all levels (base,region,configured,site,user)
  --site <SITE_ID>    Restrict configured/site levels to a specific WFO (e.g., RLX, OAX)
  --user <USER_ID>    Restrict user level to a specific username
  --match <glob>      Only include files matching filename glob (e.g., "*Wind*")

Paths & Output:
  --root <path>       Override utility root (default: /awips2/edex/data/utility)
  -o, --output <file> Output .tar.gz path (default: /tmp/awips_export_<timestamp>.tar.gz)
  --list-only         Dry-run: list matching files without creating a tarball
  -h, --help          Show this help message

Examples:
  # Collect only site & user GFE procedures and smartTools:
  ./awips_collect.sh --procedures --smart-tools --levels site,user

  # Collect GFE procedures, smartTools, and utilities including base for site RLX:
  ./awips_collect.sh --procedures --smart-tools --utilities --include-base --site RLX

  # Collect D2D procedures and bundles for site/user:
  ./awips_collect.sh --d2d-procedures --d2d-bundles --levels site,user

  # Full export of /awips2/edex/data/utility:
  ./awips_collect.sh --full --all-levels
EOF
}

LIST_ONLY=0

while [[ $# -gt 0 ]]; do
    case "$1" in
        --procedures)
            CAT_PROCEDURES=1; ANY_CAT_SET=1; shift ;;
        --smart-tools|--smarttools)
            CAT_SMARTTOOLS=1; ANY_CAT_SET=1; shift ;;
        --utilities)
            CAT_UTILITIES=1; ANY_CAT_SET=1; shift ;;
        --text-utilities|--textutilities)
            CAT_TEXTUTILITIES=1; ANY_CAT_SET=1; shift ;;
        --gfe-config|--gfeconfig)
            CAT_GFECONFIG=1; ANY_CAT_SET=1; shift ;;
        --gfe-all)
            CAT_PROCEDURES=1; CAT_SMARTTOOLS=1; CAT_UTILITIES=1
            CAT_TEXTUTILITIES=1; CAT_GFECONFIG=1; ANY_CAT_SET=1; shift ;;
        --d2d-procedures)
            CAT_D2D_PROCEDURES=1; ANY_CAT_SET=1; shift ;;
        --d2d-bundles)
            CAT_D2D_BUNDLES=1; ANY_CAT_SET=1; shift ;;
        --menus)
            CAT_MENUS=1; ANY_CAT_SET=1; shift ;;
        --d2d-all)
            CAT_D2D_PROCEDURES=1; CAT_D2D_BUNDLES=1; CAT_MENUS=1; ANY_CAT_SET=1; shift ;;
        --full|--all)
            FULL_EXPORT=1; ANY_CAT_SET=1; shift ;;
        --levels)
            LEVELS="${2:-}"; shift 2 ;;
        --include-base)
            if [[ ",$LEVELS," != *",base,"* ]]; then
                LEVELS="base,$LEVELS"
            fi
            shift ;;
        --all-levels)
            LEVELS="base,region,configured,site,user"; shift ;;
        --site)
            SITE_FILTER="${2:-}"; shift 2 ;;
        --user)
            USER_FILTER="${2:-}"; shift 2 ;;
        --match|--name)
            NAME_MATCH="${2:-}"; shift 2 ;;
        --root)
            UTILITY_ROOT="${2:-}"; shift 2 ;;
        -o|--output)
            OUTPUT_FILE="${2:-}"; shift 2 ;;
        --list-only)
            LIST_ONLY=1; shift ;;
        -h|--help)
            usage; exit 0 ;;
        *)
            echo "Unknown option: $1" >&2
            usage >&2
            exit 1 ;;
    esac
done

# Default to all GFE + D2D categories if none were explicitly passed
if [[ $ANY_CAT_SET -eq 0 ]]; then
    CAT_PROCEDURES=1
    CAT_SMARTTOOLS=1
    CAT_UTILITIES=1
    CAT_TEXTUTILITIES=1
    CAT_GFECONFIG=1
    CAT_D2D_PROCEDURES=1
    CAT_D2D_BUNDLES=1
    CAT_MENUS=1
fi

UTILITY_ROOT="${UTILITY_ROOT%/}"
if [[ ! -d "$UTILITY_ROOT" ]]; then
    echo "ERROR: Utility root directory not found: $UTILITY_ROOT" >&2
    echo "Use --root /path/to/utility if running against a non-standard directory." >&2
    exit 1
fi

IFS=',' read -r -a LEVEL_ARR <<< "$LEVELS"

TMP_LIST="$(mktemp)"
trap 'rm -f "$TMP_LIST"' EXIT

add_search_dir() {
    local rel_dir="$1"
    if [[ -d "$UTILITY_ROOT/$rel_dir" ]]; then
        if [[ -n "$NAME_MATCH" ]]; then
            find "$UTILITY_ROOT/$rel_dir" -type f \
                ! -name "*.pyc" ! -name "*.pyo" ! -name "*.md5" \
                ! -path "*/__pycache__/*" \
                -name "$NAME_MATCH" >> "$TMP_LIST"
        else
            find "$UTILITY_ROOT/$rel_dir" -type f \
                ! -name "*.pyc" ! -name "*.pyo" ! -name "*.md5" \
                ! -path "*/__pycache__/*" >> "$TMP_LIST"
        fi
    fi
}

collect_for_level_and_id() {
    local static_type="$1"  # cave_static or common_static
    local level="$2"        # base, region, configured, site, user
    local id_dir="$3"       # empty for base, or specific ID

    local prefix="$static_type/$level"
    if [[ -n "$id_dir" ]]; then
        prefix="$prefix/$id_dir"
    fi

    if [[ $FULL_EXPORT -eq 1 ]]; then
        add_search_dir "$prefix"
        return
    fi

    if [[ "$static_type" == "cave_static" ]]; then
        if [[ $CAT_PROCEDURES -eq 1 ]]; then add_search_dir "$prefix/gfe/userPython/procedures"; fi
        if [[ $CAT_SMARTTOOLS -eq 1 ]]; then add_search_dir "$prefix/gfe/userPython/smartTools"; fi
        if [[ $CAT_UTILITIES -eq 1 ]]; then add_search_dir "$prefix/gfe/userPython/utilities"; fi
        if [[ $CAT_TEXTUTILITIES -eq 1 ]]; then add_search_dir "$prefix/gfe/userPython/textUtilities"; fi
        if [[ $CAT_GFECONFIG -eq 1 ]]; then
            add_search_dir "$prefix/gfe/userPython/gfeConfig"
            add_search_dir "$prefix/gfe/config"
        fi
        if [[ $CAT_D2D_PROCEDURES -eq 1 ]]; then add_search_dir "$prefix/procedures"; fi
        if [[ $CAT_D2D_BUNDLES -eq 1 ]]; then add_search_dir "$prefix/bundles"; fi
        if [[ $CAT_MENUS -eq 1 ]]; then add_search_dir "$prefix/menus"; fi
    elif [[ "$static_type" == "common_static" ]]; then
        if [[ $CAT_GFECONFIG -eq 1 ]]; then add_search_dir "$prefix/gfe"; fi
        if [[ $CAT_UTILITIES -eq 1 ]]; then add_search_dir "$prefix/gfe/python"; fi
        if [[ $CAT_TEXTUTILITIES -eq 1 ]]; then add_search_dir "$prefix/gfe/textproducts"; fi
    fi
}

for static_type in cave_static common_static; do
    if [[ ! -d "$UTILITY_ROOT/$static_type" ]]; then continue; fi
    for level in "${LEVEL_ARR[@]}"; do
        level="$(echo "$level" | tr -d '[:space:]')"
        if [[ -z "$level" ]]; then continue; fi
        level_path="$UTILITY_ROOT/$static_type/$level"
        if [[ ! -d "$level_path" ]]; then continue; fi

        if [[ "$level" == "base" ]]; then
            collect_for_level_and_id "$static_type" "base" ""
        elif [[ "$level" == "configured" || "$level" == "site" ]]; then
            if [[ -n "$SITE_FILTER" ]]; then
                collect_for_level_and_id "$static_type" "$level" "$SITE_FILTER"
            else
                for id_path in "$level_path"/*; do
                    if [[ ! -d "$id_path" ]]; then continue; fi
                    collect_for_level_and_id "$static_type" "$level" "$(basename "$id_path")"
                done
            fi
        elif [[ "$level" == "user" ]]; then
            if [[ -n "$USER_FILTER" ]]; then
                collect_for_level_and_id "$static_type" "user" "$USER_FILTER"
            else
                for id_path in "$level_path"/*; do
                    if [[ ! -d "$id_path" ]]; then continue; fi
                    collect_for_level_and_id "$static_type" "user" "$(basename "$id_path")"
                done
            fi
        else
            # region or other level
            for id_path in "$level_path"/*; do
                if [[ -d "$id_path" ]]; then
                    collect_for_level_and_id "$static_type" "$level" "$(basename "$id_path")"
                fi
            done
        fi
    done
done

# Convert absolute paths to relative paths under UTILITY_ROOT and deduplicate
REL_LIST="$(mktemp)"
trap 'rm -f "$TMP_LIST" "$REL_LIST"' EXIT

if [[ -s "$TMP_LIST" ]]; then
    sed "s|^${UTILITY_ROOT}/||" "$TMP_LIST" | sort -u > "$REL_LIST"
fi

FILE_COUNT=$(wc -l < "$REL_LIST" | tr -d '[:space:]')

if [[ "$FILE_COUNT" -eq 0 ]]; then
    echo "No matching files found under $UTILITY_ROOT for the selected filters." >&2
    echo "  Levels: $LEVELS" >&2
    [[ -n "$SITE_FILTER" ]] && echo "  Site filter: $SITE_FILTER" >&2
    [[ -n "$USER_FILTER" ]] && echo "  User filter: $USER_FILTER" >&2
    exit 1
fi

if [[ $LIST_ONLY -eq 1 ]]; then
    cat "$REL_LIST"
    echo "----------------------------------------------------------------" >&2
    echo "Total matching files: $FILE_COUNT" >&2
    exit 0
fi

mkdir -p "$(dirname "$OUTPUT_FILE")"
tar -C "$UTILITY_ROOT" -czf "$OUTPUT_FILE" -T "$REL_LIST"

ARCHIVE_SIZE="$(du -h "$OUTPUT_FILE" | awk '{print $1}')"
echo "================================================================"
echo "AWIPS Export Complete!"
echo "  Root:        $UTILITY_ROOT"
echo "  Levels:      $LEVELS"
echo "  Files:       $FILE_COUNT"
echo "  Archive:     $OUTPUT_FILE ($ARCHIVE_SIZE)"
echo "================================================================"
