#!/bin/bash
set -e

# Database Export Script for MotoVaultPro
# Exports PostgreSQL database for deployment migration
# Usage: ./scripts/export-database.sh [options]

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
EXPORT_DIR="${PROJECT_ROOT}/database-exports"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Environment-based container names
CONTAINER_NAME=""  # Will be set based on environment selection
ENVIRONMENT=""     # production or staging

# Default values
EXPORT_FORMAT="sql"
COMPRESS=true
INCLUDE_SCHEMA=true
INCLUDE_DATA=true
EXPORT_NAME=""  # Will be set after environment selection

# Function to print colored output
print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_env() {
    echo -e "${BLUE}[ENV]${NC} $1"
}

# Function to select environment
select_environment() {
    if [ -n "$ENVIRONMENT" ]; then
        # Environment already set via command line
        return
    fi

    echo ""
    echo -e "${BLUE}========================================${NC}"
    echo -e "${BLUE}  MotoVaultPro Database Export${NC}"
    echo -e "${BLUE}========================================${NC}"
    echo ""
    echo "Select environment to export from:"
    echo ""
    echo "  1) Production  (mvp-postgres)"
    echo "  2) Staging     (mvp-postgres-staging)"
    echo ""
    read -p "Enter choice [1-2]: " ENV_CHOICE

    case $ENV_CHOICE in
        1)
            ENVIRONMENT="production"
            CONTAINER_NAME="mvp-postgres"
            ;;
        2)
            ENVIRONMENT="staging"
            CONTAINER_NAME="mvp-postgres-staging"
            ;;
        *)
            print_error "Invalid choice. Please enter 1 or 2."
            exit 1
            ;;
    esac

    echo ""
    print_env "Selected environment: ${ENVIRONMENT}"
    print_env "Container: ${CONTAINER_NAME}"
    echo ""
}

# Function to set container name based on environment
set_container_from_environment() {
    case $ENVIRONMENT in
        production|prod)
            ENVIRONMENT="production"
            CONTAINER_NAME="mvp-postgres"
            ;;
        staging|stage)
            ENVIRONMENT="staging"
            CONTAINER_NAME="mvp-postgres-staging"
            ;;
        *)
            print_error "Invalid environment: $ENVIRONMENT"
            print_error "Valid options: production, staging"
            exit 1
            ;;
    esac
}

# Function to show usage
show_usage() {
    cat << EOF
Database Export Script for MotoVaultPro

Usage: $0 [options]

Options:
    -h, --help              Show this help message
    -e, --env ENV           Environment: production or staging (prompts if not specified)
    -f, --format FORMAT     Export format: sql, custom, directory (default: sql)
    -o, --output NAME       Custom export filename (without extension)
    -n, --no-compress       Don't compress the export
    --schema-only           Export schema only (no data)
    --data-only             Export data only (no schema)
    --exclude-table TABLE   Exclude specific table(s) (can be used multiple times)
    --include-table TABLE   Include only specific table(s) (can be used multiple times)
    -c, --container NAME    Override container name (ignores environment selection)

Environments:
    production (prod)       Uses container: mvp-postgres
    staging (stage)         Uses container: mvp-postgres-staging

Examples:
    # Interactive environment selection
    $0

    # Export from production
    $0 --env production

    # Export from staging
    $0 --env staging

    # Schema only export from production
    $0 --env prod --schema-only

    # Export specific tables from staging
    $0 -e staging --include-table vehicles --include-table fuel_logs

    # Custom format for pg_restore
    $0 --env production --format custom --output my_backup

EOF
    exit 0
}

# Parse command line arguments
EXCLUDE_TABLES=()
INCLUDE_TABLES=()
CONTAINER_OVERRIDE=""

while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            ;;
        -e|--env)
            ENVIRONMENT="$2"
            shift 2
            ;;
        -f|--format)
            EXPORT_FORMAT="$2"
            shift 2
            ;;
        -o|--output)
            EXPORT_NAME="$2"
            shift 2
            ;;
        -n|--no-compress)
            COMPRESS=false
            shift
            ;;
        --schema-only)
            INCLUDE_DATA=false
            shift
            ;;
        --data-only)
            INCLUDE_SCHEMA=false
            shift
            ;;
        --exclude-table)
            EXCLUDE_TABLES+=("$2")
            shift 2
            ;;
        --include-table)
            INCLUDE_TABLES+=("$2")
            shift 2
            ;;
        -c|--container)
            CONTAINER_OVERRIDE="$2"
            shift 2
            ;;
        *)
            print_error "Unknown option: $1"
            show_usage
            ;;
    esac
done

# Handle environment selection
if [ -n "$CONTAINER_OVERRIDE" ]; then
    # Container explicitly specified, use it directly
    CONTAINER_NAME="$CONTAINER_OVERRIDE"
    ENVIRONMENT="custom"
    print_info "Using custom container: $CONTAINER_NAME"
elif [ -n "$ENVIRONMENT" ]; then
    # Environment specified via command line
    set_container_from_environment
else
    # No environment specified, prompt user
    select_environment
fi

# Set default export name with environment prefix
if [ -z "$EXPORT_NAME" ]; then
    EXPORT_NAME="motovaultpro_${ENVIRONMENT}_export_${TIMESTAMP}"
fi

# Create export directory if it doesn't exist
mkdir -p "${EXPORT_DIR}"

# Check if container is running
print_info "Checking if PostgreSQL container is running..."
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
    print_error "PostgreSQL container '${CONTAINER_NAME}' is not running"
    print_info "Start it with: docker compose up -d mvp-postgres"
    exit 1
fi

# Build pg_dump options
PG_DUMP_OPTS=""

# Schema/Data options
if [ "$INCLUDE_SCHEMA" = false ]; then
    PG_DUMP_OPTS="$PG_DUMP_OPTS --data-only"
fi

if [ "$INCLUDE_DATA" = false ]; then
    PG_DUMP_OPTS="$PG_DUMP_OPTS --schema-only"
fi

# Format options
case $EXPORT_FORMAT in
    sql)
        PG_DUMP_OPTS="$PG_DUMP_OPTS --format=plain"
        EXPORT_EXT="sql"
        ;;
    custom)
        PG_DUMP_OPTS="$PG_DUMP_OPTS --format=custom"
        EXPORT_EXT="dump"
        COMPRESS=false  # Custom format is already compressed
        ;;
    directory)
        PG_DUMP_OPTS="$PG_DUMP_OPTS --format=directory"
        EXPORT_EXT="dir"
        COMPRESS=false  # Directory format doesn't need compression
        ;;
    *)
        print_error "Invalid format: $EXPORT_FORMAT"
        exit 1
        ;;
esac

# Exclude tables
for table in "${EXCLUDE_TABLES[@]}"; do
    PG_DUMP_OPTS="$PG_DUMP_OPTS --exclude-table=$table"
done

# Include tables
for table in "${INCLUDE_TABLES[@]}"; do
    PG_DUMP_OPTS="$PG_DUMP_OPTS --table=$table"
done

# Set output file path
if [ "$EXPORT_FORMAT" = "directory" ]; then
    OUTPUT_PATH="${EXPORT_DIR}/${EXPORT_NAME}.${EXPORT_EXT}"
    mkdir -p "${OUTPUT_PATH}"
else
    OUTPUT_PATH="${EXPORT_DIR}/${EXPORT_NAME}.${EXPORT_EXT}"
fi

# Export database
print_info "Starting database export..."
print_info "Environment: ${ENVIRONMENT}"
print_info "Container: ${CONTAINER_NAME}"
print_info "Format: ${EXPORT_FORMAT}"
print_info "Output: ${OUTPUT_PATH}"

if [ "$EXPORT_FORMAT" = "directory" ]; then
    # For directory format, we need to export inside container then copy out
    docker exec "$CONTAINER_NAME" sh -c "pg_dump -U postgres -d motovaultpro $PG_DUMP_OPTS -f /tmp/export_dir" || {
        print_error "Database export failed"
        exit 1
    }
    docker cp "${CONTAINER_NAME}:/tmp/export_dir/." "${OUTPUT_PATH}/"
    docker exec "$CONTAINER_NAME" rm -rf /tmp/export_dir
else
    # For SQL and custom formats
    docker exec "$CONTAINER_NAME" pg_dump -U postgres -d motovaultpro $PG_DUMP_OPTS > "${OUTPUT_PATH}" || {
        print_error "Database export failed"
        exit 1
    }
fi

print_info "Database exported successfully"

# Compress if requested and format is SQL
if [ "$COMPRESS" = true ] && [ "$EXPORT_FORMAT" = "sql" ]; then
    print_info "Compressing export..."
    gzip "${OUTPUT_PATH}"
    OUTPUT_PATH="${OUTPUT_PATH}.gz"
    print_info "Compressed to: ${OUTPUT_PATH}"
fi

# Create metadata file
METADATA_FILE="${EXPORT_DIR}/${EXPORT_NAME}_metadata.json"
cat > "${METADATA_FILE}" << EOF
{
  "export_timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "environment": "${ENVIRONMENT}",
  "container_name": "${CONTAINER_NAME}",
  "database_name": "motovaultpro",
  "export_format": "${EXPORT_FORMAT}",
  "compressed": ${COMPRESS},
  "schema_included": ${INCLUDE_SCHEMA},
  "data_included": ${INCLUDE_DATA},
  "postgresql_version": "$(docker exec "$CONTAINER_NAME" psql -U postgres -t -c 'SELECT version();' | xargs)",
  "file_path": "${OUTPUT_PATH}",
  "file_size": "$(du -h "${OUTPUT_PATH}" | cut -f1)"
}
EOF

print_info "Metadata saved to: ${METADATA_FILE}"

# Generate import instructions
IMPORT_INSTRUCTIONS="${EXPORT_DIR}/${EXPORT_NAME}_import_instructions.txt"
cat > "${IMPORT_INSTRUCTIONS}" << EOF
===========================================
MotoVaultPro Database Import Instructions
===========================================

Export Details:
- Export Date: $(date)
- Format: ${EXPORT_FORMAT}
- Compressed: ${COMPRESS}
- File: ${OUTPUT_PATH}

Import Instructions:
--------------------

1. Copy the export file to your target server:
   scp ${OUTPUT_PATH} user@server:/path/to/import/

EOF

if [ "$EXPORT_FORMAT" = "sql" ]; then
    if [ "$COMPRESS" = true ]; then
        cat >> "${IMPORT_INSTRUCTIONS}" << EOF
2. Import the database (compressed SQL):
   # Using Docker:
   gunzip -c /path/to/import/$(basename "${OUTPUT_PATH}") | docker exec -i mvp-postgres psql -U postgres -d motovaultpro

   # Direct PostgreSQL:
   gunzip -c /path/to/import/$(basename "${OUTPUT_PATH}") | psql -U postgres -d motovaultpro
EOF
    else
        cat >> "${IMPORT_INSTRUCTIONS}" << EOF
2. Import the database (SQL):
   # Using Docker:
   docker exec -i mvp-postgres psql -U postgres -d motovaultpro < /path/to/import/$(basename "${OUTPUT_PATH}")

   # Direct PostgreSQL:
   psql -U postgres -d motovaultpro < /path/to/import/$(basename "${OUTPUT_PATH}")
EOF
    fi
elif [ "$EXPORT_FORMAT" = "custom" ]; then
    cat >> "${IMPORT_INSTRUCTIONS}" << EOF
2. Import the database (custom format):
   # Using Docker:
   docker cp /path/to/import/$(basename "${OUTPUT_PATH}") mvp-postgres:/tmp/restore.dump
   docker exec mvp-postgres pg_restore -U postgres -d motovaultpro -c /tmp/restore.dump

   # Direct PostgreSQL:
   pg_restore -U postgres -d motovaultpro -c /path/to/import/$(basename "${OUTPUT_PATH}")
EOF
elif [ "$EXPORT_FORMAT" = "directory" ]; then
    cat >> "${IMPORT_INSTRUCTIONS}" << EOF
2. Import the database (directory format):
   # Using Docker:
   docker cp /path/to/import/$(basename "${OUTPUT_PATH}") mvp-postgres:/tmp/restore_dir
   docker exec mvp-postgres pg_restore -U postgres -d motovaultpro -c /tmp/restore_dir

   # Direct PostgreSQL:
   pg_restore -U postgres -d motovaultpro -c /path/to/import/$(basename "${OUTPUT_PATH}")
EOF
fi

cat >> "${IMPORT_INSTRUCTIONS}" << EOF

Notes:
------
- The -c flag drops existing database objects before recreating them
- Ensure the target database exists before importing
- For production imports, always test on a staging environment first
- Consider creating a backup of the target database before importing

Create target database:
-----------------------
docker exec -i mvp-postgres psql -U postgres -c "CREATE DATABASE motovaultpro;"

Or if database exists and you want to start fresh:
--------------------------------------------------
docker exec -i mvp-postgres psql -U postgres -c "DROP DATABASE IF EXISTS motovaultpro;"
docker exec -i mvp-postgres psql -U postgres -c "CREATE DATABASE motovaultpro;"

EOF

print_info "Import instructions saved to: ${IMPORT_INSTRUCTIONS}"

# Summary
echo ""
print_info "==============================================="
print_info "Database Export Complete!"
print_info "==============================================="
print_info "Environment: ${ENVIRONMENT}"
print_info "Container: ${CONTAINER_NAME}"
print_info "Export file: ${OUTPUT_PATH}"
print_info "Metadata: ${METADATA_FILE}"
print_info "Instructions: ${IMPORT_INSTRUCTIONS}"
print_info "Size: $(du -h "${OUTPUT_PATH}" | cut -f1)"
echo ""
print_info "To import this database on another deployment:"
print_info "1. Copy the export file to the target server"
print_info "2. Follow the instructions in ${IMPORT_INSTRUCTIONS}"
echo ""
