#!/bin/bash
###############################################################################
# migration-pack.sh
#
# Creates an encrypted migration archive of all non-git ClaudeTools data.
# Works in Git Bash on Windows AND native Linux bash.
#
# Usage: ./migration-pack.sh [source_dir]
#   source_dir  Path to ClaudeTools repo (default: script's parent directory)
#
# Output: claudetools-migration-YYYYMMDD.tar.gpg in current working directory
###############################################################################

set -euo pipefail

# ---------------------------------------------------------------------------
# Globals
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCE_DIR="${1:-"$(cd "$SCRIPT_DIR/.." && pwd)"}"
DATE_STAMP="$(date +%Y%m%d)"
ARCHIVE_NAME="claudetools-migration-${DATE_STAMP}.tar.gpg"
STAGING_DIR=""
MANIFEST_FILE="MIGRATION_MANIFEST.txt"
WARN_COUNT=0
COPY_COUNT=0

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
log_info()    { echo "[INFO]    $*"; }
log_ok()      { echo "[OK]      $*"; }
log_warn()    { echo "[WARNING] $*"; WARN_COUNT=$((WARN_COUNT + 1)); }
log_error()   { echo "[ERROR]   $*"; }

cleanup() {
    if [[ -n "$STAGING_DIR" && -d "$STAGING_DIR" ]]; then
        log_info "Cleaning up staging directory..."
        rm -rf "$STAGING_DIR"
    fi
}
trap cleanup EXIT

check_tool() {
    if ! command -v "$1" &>/dev/null; then
        log_error "Required tool not found: $1"
        exit 1
    fi
}

# Copy a single file into the staging area, preserving relative path.
# Warns and continues if the source does not exist.
stage_file() {
    local rel_path="$1"
    local src="${SOURCE_DIR}/${rel_path}"
    local dst="${STAGING_DIR}/${rel_path}"

    if [[ ! -e "$src" ]]; then
        log_warn "File not found, skipping: ${rel_path}"
        return
    fi

    mkdir -p "$(dirname "$dst")"
    cp -a "$src" "$dst"
    COPY_COUNT=$((COPY_COUNT + 1))
    log_ok "Staged: ${rel_path}"
}

# Copy an entire directory into the staging area.
stage_dir() {
    local rel_path="$1"
    local src="${SOURCE_DIR}/${rel_path}"
    local dst="${STAGING_DIR}/${rel_path}"

    if [[ ! -d "$src" ]]; then
        log_warn "Directory not found, skipping: ${rel_path}"
        return
    fi

    mkdir -p "$(dirname "$dst")"
    cp -a "$src" "$dst"
    COPY_COUNT=$((COPY_COUNT + 1))
    log_ok "Staged directory: ${rel_path}"
}

# Detect the Claude AI context directory based on platform conventions.
# On Windows (Git Bash), the repo path D:\ClaudeTools becomes D--ClaudeTools.
# On Linux/macOS, /home/user/ClaudeTools becomes -home-user-ClaudeTools.
detect_claude_context_dir() {
    local claude_projects_base="${HOME}/.claude/projects"

    if [[ ! -d "$claude_projects_base" ]]; then
        echo ""
        return
    fi

    # Try Windows-style mapping first: D:\ClaudeTools -> D--ClaudeTools
    # Convert SOURCE_DIR from /d/path or D:/path to D--path
    local win_name=""
    if [[ "$SOURCE_DIR" =~ ^/([a-zA-Z])/(.*) ]]; then
        # Git Bash path like /d/ClaudeTools
        local drive="${BASH_REMATCH[1]^^}"
        local rest="${BASH_REMATCH[2]}"
        win_name="${drive}--${rest//\//-}"
    elif [[ "$SOURCE_DIR" =~ ^([a-zA-Z]):(.*) ]]; then
        # Windows path like D:\ClaudeTools or D:/ClaudeTools
        local drive="${BASH_REMATCH[1]^^}"
        local rest="${BASH_REMATCH[2]}"
        rest="${rest//\\/-}"
        rest="${rest//\//-}"
        rest="${rest#-}"
        win_name="${drive}--${rest}"
    fi

    if [[ -n "$win_name" && -d "${claude_projects_base}/${win_name}" ]]; then
        echo "${claude_projects_base}/${win_name}"
        return
    fi

    # Try Linux-style mapping: absolute path with slashes replaced by dashes
    local linux_name="${SOURCE_DIR//\//-}"
    linux_name="${linux_name#-}"
    if [[ -d "${claude_projects_base}/${linux_name}" ]]; then
        echo "${claude_projects_base}/${linux_name}"
        return
    fi

    echo ""
}

# Write a manifest of everything in the staging directory.
write_manifest() {
    local manifest="${STAGING_DIR}/${MANIFEST_FILE}"
    {
        echo "============================================================"
        echo " ClaudeTools Migration Manifest"
        echo " Created: $(date '+%Y-%m-%d %H:%M:%S')"
        echo " Source:  ${SOURCE_DIR}"
        echo " Host:    $(hostname)"
        echo "============================================================"
        echo ""
        echo "Contents:"
        echo "------------------------------------------------------------"
        # Use find to list all files with sizes.
        # On Git Bash, stat flags differ from GNU coreutils; use portable approach.
        find "$STAGING_DIR" -type f ! -name "$MANIFEST_FILE" -print0 | while IFS= read -r -d '' file; do
            local rel="${file#"${STAGING_DIR}/"}"
            local size
            size="$(wc -c < "$file" 2>/dev/null || echo "?")"
            printf "  %-60s %s bytes\n" "$rel" "$size"
        done | sort
        echo "------------------------------------------------------------"
        echo ""
        # Directory count and file count
        local dir_count file_count total_size
        dir_count="$(find "$STAGING_DIR" -mindepth 1 -type d | wc -l)"
        file_count="$(find "$STAGING_DIR" -type f ! -name "$MANIFEST_FILE" | wc -l)"
        total_size="$(find "$STAGING_DIR" -type f ! -name "$MANIFEST_FILE" -print0 | xargs -0 wc -c 2>/dev/null | tail -n1 | awk '{print $1}')"
        echo "Directories: ${dir_count}"
        echo "Files:       ${file_count}"
        echo "Total size:  ${total_size:-0} bytes"
    } > "$manifest"
    log_ok "Manifest written: ${MANIFEST_FILE}"
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
main() {
    echo "============================================================"
    echo " ClaudeTools Migration Packer"
    echo " $(date '+%Y-%m-%d %H:%M:%S')"
    echo "============================================================"
    echo ""

    # Validate source directory
    if [[ ! -d "$SOURCE_DIR" ]]; then
        log_error "Source directory does not exist: ${SOURCE_DIR}"
        exit 1
    fi
    log_info "Source directory: ${SOURCE_DIR}"

    # Check required tools
    check_tool tar
    check_tool gpg
    log_ok "Required tools available (tar, gpg)"

    # Create staging directory
    STAGING_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t 'migration')"
    log_info "Staging directory: ${STAGING_DIR}"
    echo ""

    # ------------------------------------------------------------------
    # Stage individual files
    # ------------------------------------------------------------------
    log_info "--- Staging individual files ---"
    stage_file "credentials.md"
    stage_file ".env"
    stage_file ".mcp.json"
    stage_file "dataforth-notifications-creds.txt"
    stage_file ".claude/settings.local.json"
    stage_file "projects/solverbot/.env"
    stage_file "session-logs/2026-02-25-session.md"
    echo ""

    # ------------------------------------------------------------------
    # Stage directories
    # ------------------------------------------------------------------
    log_info "--- Staging directories ---"
    stage_dir "imported-conversations"
    stage_dir "backups"
    stage_dir "clients/gurushow"
    echo ""

    # ------------------------------------------------------------------
    # Stage Claude AI context
    # ------------------------------------------------------------------
    log_info "--- Staging Claude AI context ---"
    local claude_ctx
    claude_ctx="$(detect_claude_context_dir)"

    if [[ -n "$claude_ctx" && -d "$claude_ctx" ]]; then
        local ctx_dst="${STAGING_DIR}/claude-context"
        mkdir -p "$ctx_dst"
        cp -a "$claude_ctx"/. "$ctx_dst/"
        COPY_COUNT=$((COPY_COUNT + 1))
        log_ok "Staged Claude context from: ${claude_ctx}"
    else
        log_warn "Claude AI context directory not found. Looked under \$HOME/.claude/projects/"
        log_warn "You may need to manually copy this after migration."
    fi
    echo ""

    # ------------------------------------------------------------------
    # Write manifest
    # ------------------------------------------------------------------
    log_info "--- Writing manifest ---"
    write_manifest
    echo ""

    # ------------------------------------------------------------------
    # Create encrypted archive
    # ------------------------------------------------------------------
    log_info "--- Creating encrypted archive ---"
    log_info "You will be prompted for a passphrase to encrypt the archive."
    echo ""

    # Create tar from staging contents, then encrypt with GPG symmetric.
    # Use --batch only if GPG_PASSPHRASE env var is set (for automation).
    local tar_tmp="${STAGING_DIR}.tar"

    tar -cf "$tar_tmp" -C "$STAGING_DIR" .

    if [[ -n "${GPG_PASSPHRASE:-}" ]]; then
        echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 \
            --symmetric --cipher-algo AES256 \
            --output "$ARCHIVE_NAME" "$tar_tmp"
    else
        gpg --symmetric --cipher-algo AES256 \
            --output "$ARCHIVE_NAME" "$tar_tmp"
    fi

    rm -f "$tar_tmp"

    if [[ ! -f "$ARCHIVE_NAME" ]]; then
        log_error "Archive creation failed."
        exit 1
    fi

    local archive_size
    archive_size="$(wc -c < "$ARCHIVE_NAME")"

    echo ""
    echo "============================================================"
    echo " Migration Pack Complete"
    echo "============================================================"
    echo ""
    echo "  Archive:    $(pwd)/${ARCHIVE_NAME}"
    echo "  Size:       ${archive_size} bytes"
    echo "  Items:      ${COPY_COUNT} files/directories staged"
    echo "  Warnings:   ${WARN_COUNT}"
    echo "  Encrypted:  AES-256 (GPG symmetric)"
    echo ""
    echo "  To restore, run:"
    echo "    ./migration-restore.sh ${ARCHIVE_NAME}"
    echo ""
    log_ok "Done."
}

main "$@"
