#!/bin/bash

# author Gennadiy Tselischev
# revised by Oleksandr Molchanov
# .wpress support added
# .wpress parser fixed for new AI1WM format (hash suffix in prefix field)
# .wpress extraction path fixed (wp-content files go to wp-content/, not WP root)
# SERVMASK_PREFIX_ database placeholder fix added
# Fresh WordPress install option added
# Auto theme/plugin activation added (AI1WM clears these in the dump intentionally)

# Colors
ENDCOLOR="\e[0m"
RED="\e[31m"
GREEN="\e[32m"
BOLDGREEN="\e[1;32m"
YELLOW="\e[33m"
BLUE="\e[34m"

SEPARATOR="\n$(printf '%.0s-' {1..40})\n"
LOG_FILE="wprestor_log"

# Global state
FRESH_INSTALL=false
ORIGINAL_PREFIX="wp_"
ORIGINAL_URL=""
ORIGINAL_THEME=""
ORIGINAL_PLUGINS_LIST=""   # newline-separated plugin paths from package.json
SAVED_TEMPLATE=""          # template saved from SERVMASK_ table before rename
SAVED_STYLESHEET=""        # stylesheet saved from SERVMASK_ table before rename

err() {
    echo -e "${RED}ERROR: ${1}${ENDCOLOR}"
    exit 1
}

check_user() {
    local user_id
    user_id="$(id -u)"
    [[ "${user_id}" -eq 0 ]] && err "You should not run it as root!"
}

check_home_directory() {
    ! grep "^${HOME}" <<< "${PWD}" && err "You should run it under user homedir!"
}

show_disclaimer() {
    echo -e "${YELLOW}WARNING:${ENDCOLOR} This script will move all files in the current directory to a backup folder, excluding: *.tar.gz, *.zip, *.wpress, *.sh, *.sql, cgi-bin, .well-known."
    echo -e "${YELLOW}Current directory contents:${ENDCOLOR}"
    ls -la
    echo -e "${YELLOW}Do you understand and accept the responsibility for the consequences? [y/n]${ENDCOLOR}"
    read -rp "> " user_response
    [[ ! "${user_response}" =~ ^[yY](es)?$ ]] && err "User did not accept the disclaimer. Exiting."
    echo -e "${GREEN}Proceeding with the script...${ENDCOLOR}"
}

backup_unwanted_files() {
    local backup_dir="previous_folder_backup"
    unwanted_items=$(find . -maxdepth 1 \( \
        ! -name "." ! -name ".." \
        ! -name "*.tar.gz" ! -name "*.zip" ! -name "*.wpress" \
        ! -name "*.sh" ! -name "*.sql" \
        ! -name "cgi-bin" ! -name ".well-known" \
        ! -name "$backup_dir" \
    \))
    if [[ -n "$unwanted_items" ]]; then
        echo -e "${BLUE}Moving existing files to ${backup_dir}...${ENDCOLOR}"
        mkdir -p "$backup_dir"
        for item in $unwanted_items; do
            [[ "$item" != "." ]] && mv "$item" "$backup_dir"
        done
        echo -e "${GREEN}Done.${ENDCOLOR}"
    else
        echo -e "${GREEN}No files to move.${ENDCOLOR}"
    fi
}

find_backup() {
    echo -e "\nAvailable backups to restore:\n"
    local BACKUPS=()
    while IFS= read -r -d $'\0' f; do
        BACKUPS+=("$f")
    done < <(find "${PWD}" -maxdepth 1 -type f \
        \( -name "*.zip" -o -name "*.tar.gz" -o -name "*.wpress" \) -print0)

    [[ "${#BACKUPS[@]}" -eq 0 ]] && err "No backups found in ${PWD}"

    if [[ "${#BACKUPS[@]}" -gt 1 ]]; then
        local NUM=1
        for i in "${BACKUPS[@]}"; do echo "${NUM}. $i"; NUM=$((NUM+1)); done | column -t
        local BACKUP_CHOICE
        read -rp "> Choose the backup: " BACKUP_CHOICE
        [[ ! "${BACKUP_CHOICE}" =~ ^[1-9][0-9]*$ ]] && err "Invalid choice"
        local IDX=$((BACKUP_CHOICE-1))
        [[ -z "${BACKUPS[$IDX]:-}" ]] && err "Invalid choice"
        CHOSEN_BACKUP="${BACKUPS[$IDX]}"
    else
        CHOSEN_BACKUP="${BACKUPS[0]}"
        echo "${BACKUPS[0]}"
    fi

    echo -e "${SEPARATOR}"
    local CHOICE
    read -rp "> Do you want to proceed? [y/n]: " CHOICE
    [[ ! "${CHOICE}" =~ ^[yY](es)?$ ]] && err "Ok, next time"

    BACKUP="$(basename "${CHOSEN_BACKUP}")"
    BACKUP_TYPE=""
    [[ "$BACKUP" == *.wpress ]] && BACKUP_TYPE="wpress"
    [[ "$BACKUP" == *.tar.gz ]] && BACKUP_TYPE="targz"
    [[ "$BACKUP" == *.zip    ]] && BACKUP_TYPE="zip"
}

# ─── Create DB via cPanel uapi ────────────────────────────────────────────────
create_database() {
    database_exists() {
        local db_name="$1"
        local existing
        existing=$(uapi --output=jsonpretty --user="$(whoami)" Mysql list_databases 2>/dev/null \
            | python3 -c "
import sys, json
try:
    d = json.load(sys.stdin)
    for x in d['result']['data']:
        print(x['database'])
except:
    pass
" 2>/dev/null)
        grep -qx "$db_name" <<< "$existing"
    }

    while true; do
        local RANDOM_NUMBER
        RANDOM_NUMBER=$(shuf -i 100-999 -n 1)
        DB_NAME="${USER}_wpr${RANDOM_NUMBER}"
        database_exists "$DB_NAME" || break
    done

    DB_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 12)

    echo -e "\n${YELLOW}Database credentials (also saved to $LOG_FILE):${ENDCOLOR}"
    echo -e "  ${GREEN}Name:${ENDCOLOR}     $DB_NAME"
    echo -e "  ${GREEN}User:${ENDCOLOR}     $DB_NAME"
    echo -e "  ${GREEN}Password:${ENDCOLOR} $DB_PASS"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - DB: Name=$DB_NAME, User=$DB_NAME, Password=$DB_PASS" >> "$LOG_FILE"

    echo -e "\n${BLUE}Creating database...${ENDCOLOR}"
    uapi Mysql create_database name="$DB_NAME" >> "$LOG_FILE" 2>&1 \
        && echo -e "${GREEN}Database created.${ENDCOLOR}" \
        || echo -e "${RED}Failed to create database. Check manually.${ENDCOLOR}"

    echo -e "${BLUE}Creating user...${ENDCOLOR}"
    uapi Mysql create_user name="$DB_NAME" password="$DB_PASS" >> "$LOG_FILE" 2>&1 \
        && echo -e "${GREEN}User created.${ENDCOLOR}" \
        || echo -e "${RED}Failed to create user. Check manually.${ENDCOLOR}"

    echo -e "${BLUE}Granting privileges...${ENDCOLOR}"
    uapi Mysql set_privileges_on_database user="$DB_NAME" database="$DB_NAME" privileges=ALL >> "$LOG_FILE" 2>&1 \
        && echo -e "${GREEN}Privileges granted.${ENDCOLOR}" \
        || echo -e "${RED}Failed to grant privileges. Check manually.${ENDCOLOR}"

    echo -e "${SEPARATOR}"
}

# ─── Install fresh WordPress ──────────────────────────────────────────────────
install_fresh_wp() {
    command -v wp &>/dev/null || err "wp-cli not found. Install from https://wp-cli.org"

    read -rp "> Enter domain name (e.g. https://example.com): " DOMAIN
    [[ -z "$DOMAIN" ]] && err "No domain name provided."

    create_database

    echo -e "${BLUE}Downloading WordPress core...${ENDCOLOR}"
    wp core download || err "Failed to download WordPress core."

    echo -e "${BLUE}Creating wp-config.php...${ENDCOLOR}"
    wp config create \
        --dbname="${DB_NAME}" \
        --dbuser="${DB_NAME}" \
        --dbpass="${DB_PASS}" \
        || err "Failed to create wp-config.php."

    local WP_ADMIN_USER WP_ADMIN_PASS
    WP_ADMIN_USER="$(openssl rand -hex 4)"
    WP_ADMIN_PASS="$(openssl rand -hex 8)"

    echo -e "${BLUE}Installing WordPress...${ENDCOLOR}"
    wp core install \
        --url="${DOMAIN}" \
        --title="${DOMAIN}" \
        --admin_user="${WP_ADMIN_USER}" \
        --admin_password="${WP_ADMIN_PASS}" \
        --admin_email="admin@${DOMAIN//https:\/\//}" \
        || err "Failed to install WordPress."

    echo -e "${BOLDGREEN}Fresh WordPress installed!${ENDCOLOR}"
    echo -e "  ${GREEN}Admin user:${ENDCOLOR}     ${WP_ADMIN_USER}"
    echo -e "  ${GREEN}Admin password:${ENDCOLOR} ${WP_ADMIN_PASS}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Fresh WP: url=${DOMAIN}, admin=${WP_ADMIN_USER}, pass=${WP_ADMIN_PASS}" >> "$LOG_FILE"
    echo -e "${SEPARATOR}"

    FRESH_INSTALL=true
}

# ─── Extract .wpress ──────────────────────────────────────────────────────────
# Header format (4377 bytes total):
#   255 bytes  — filename (null-padded)
#   14  bytes  — file size as ASCII
#   12  bytes  — mtime as ASCII
#   4096 bytes — directory prefix (null-padded; newer AI1WM appends an 8-char
#                hex hash at the very end of this field)
#   N bytes    — file data
#   EOF marker — header with empty filename field
#
# FIX 1 — split(NUL)[0] instead of rstrip(NUL): handles the 8-byte hash that
#          newer AI1WM appends inside the prefix field.
# FIX 2 — EOF via empty filename, not all-zero block: newer AI1WM EOF blocks
#          have non-zero bytes in other fields.
# FIX 3 — extraction path: AI1WM stores wp-content contents without the
#          "wp-content/" prefix. package.json and database.sql go to WP root;
#          everything else (plugins/, themes/, …) goes to wp-content/.
extract_wpress() {
    echo -e "\n${BLUE}Extracting .wpress archive...${ENDCOLOR}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Extracting ${BACKUP} as .wpress..." >> "$LOG_FILE"

    command -v python3 &>/dev/null || err "python3 is required to extract .wpress archives"

    local ARCHIVE_PATH WP_ROOT WP_CONTENT
    ARCHIVE_PATH="$(pwd)/${BACKUP}"
    WP_ROOT="$(pwd)"
    WP_CONTENT="$(pwd)/wp-content"

    python3 - "$ARCHIVE_PATH" "$WP_ROOT" "$WP_CONTENT" <<'PYEOF'
import os, sys

src        = sys.argv[1]
wp_root    = sys.argv[2]
wp_content = sys.argv[3]

FILENAME_SIZE = 255
CONTENT_SIZE  = 14
MTIME_SIZE    = 12
PREFIX_SIZE   = 4096
HEADER_SIZE   = FILENAME_SIZE + CONTENT_SIZE + MTIME_SIZE + PREFIX_SIZE  # 4377
NUL           = b'\x00'

ROOT_FILES = {'package.json', 'database.sql'}

def decode_header(block):
    fname_bytes  = block[0:FILENAME_SIZE].split(NUL)[0]
    prefix_bytes = block[FILENAME_SIZE + CONTENT_SIZE + MTIME_SIZE:].split(NUL)[0]
    fname  = fname_bytes.decode('utf-8', errors='replace')
    size   = int(block[FILENAME_SIZE:FILENAME_SIZE + CONTENT_SIZE].rstrip(NUL) or b'0')
    mtime  = int(block[FILENAME_SIZE + CONTENT_SIZE:FILENAME_SIZE + CONTENT_SIZE + MTIME_SIZE].rstrip(NUL) or b'0')
    prefix = prefix_bytes.decode('utf-8', errors='replace')
    path   = (prefix + '/' + fname) if (prefix and prefix != '.') else fname
    return path, size, mtime

def get_base(path):
    if '/' not in path and path in ROOT_FILES:
        return wp_root
    return wp_content

def safe_path(base, rel):
    target = os.path.realpath(os.path.join(base, rel))
    base_r = os.path.realpath(base)
    if not (target == base_r or target.startswith(base_r + os.sep)):
        raise ValueError(f"Path traversal blocked: {rel}")
    return target

os.makedirs(wp_content, mode=0o755, exist_ok=True)
extracted = 0
errors    = 0

with open(src, 'rb') as f:
    while True:
        block = f.read(HEADER_SIZE)
        if not block:
            break
        if len(block) < HEADER_SIZE:
            print(f"Warning: short read ({len(block)} bytes)", file=sys.stderr)
            break
        if not block[0:FILENAME_SIZE].split(NUL)[0]:
            break

        path, size, mtime = decode_header(block)
        if not path:
            break

        base = get_base(path)
        try:
            target = safe_path(base, path)
            os.makedirs(os.path.dirname(target), mode=0o755, exist_ok=True)
            with open(target, 'wb') as out:
                remaining = size
                while remaining > 0:
                    chunk = f.read(min(1024 * 1024, remaining))
                    if not chunk:
                        raise EOFError(f"Truncated: {path}")
                    out.write(chunk)
                    remaining -= len(chunk)
            os.chmod(target, 0o644)
            os.utime(target, (mtime, mtime))
            extracted += 1
            if extracted % 500 == 0:
                print(f"  ... {extracted} files extracted", flush=True)
        except ValueError as e:
            print(f"  [SKIP] {e}", file=sys.stderr)
            f.seek(size, 1)
            errors += 1
        except Exception as e:
            print(f"  [ERROR] {path}: {e}", file=sys.stderr)
            errors += 1

print(f"Done: {extracted} files extracted, {errors} errors.")
if extracted == 0:
    print("ERROR: 0 files extracted!", file=sys.stderr)
    sys.exit(1)
if errors > 10:
    print(f"ERROR: too many errors ({errors})", file=sys.stderr)
    sys.exit(1)
PYEOF

    local py_exit=$?
    if [[ $py_exit -ne 0 ]]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') - Extraction FAILED for ${BACKUP}." >> "$LOG_FILE"
        err "Extraction failed. Check the log."
    fi

    echo -e "${GREEN}${BACKUP} extracted successfully!${ENDCOLOR}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ${BACKUP} extracted successfully." >> "$LOG_FILE"

    WPRESS_SQL=""
    if [[ -f "$(pwd)/database.sql" ]]; then
        WPRESS_SQL="$(pwd)/database.sql"
        echo -e "${GREEN}Found SQL dump: ${WPRESS_SQL}${ENDCOLOR}"
    else
        WPRESS_SQL="$(find "$(pwd)" -maxdepth 4 -name 'database.sql' | head -1)"
        [[ -n "$WPRESS_SQL" ]] && echo -e "${YELLOW}Found SQL dump at: ${WPRESS_SQL}${ENDCOLOR}"
    fi

    echo -e "${SEPARATOR}"
}

# ─── Read AI1WM archive metadata from package.json ───────────────────────────
# Reads: original prefix, site URL, active theme, active plugin list.
# All four values are stored by AI1WM in the archive's package.json.
# The prefix is used as-is — the user is shown it for confirmation only.
# The theme and plugin list are used later by restore_wpress_activation().
read_wpress_metadata() {
    local pkg="${PWD}/package.json"
    ORIGINAL_PREFIX="wp_"
    ORIGINAL_URL=""
    ORIGINAL_THEME=""
    ORIGINAL_PLUGINS_LIST=""

    if [[ -f "$pkg" ]]; then
        # Run all extractions in a single Python call to avoid repeated file opens
        eval "$(python3 - "$pkg" <<'PYEOF'
import json, sys

try:
    d = json.load(open(sys.argv[1]))
except Exception as e:
    print(f"ORIGINAL_PREFIX='wp_'; ORIGINAL_URL=''; ORIGINAL_THEME=''; ORIGINAL_PLUGINS_LIST=''")
    sys.exit(0)

# prefix
p = d.get('prefix', 'wp_') or 'wp_'
prefix = p if p.endswith('_') else p + '_'

# url
url = d.get('url', '') or ''

# theme (AI1WM uses 'theme' or 'stylesheet' or inside 'db' section — try all)
theme = (d.get('theme') or d.get('stylesheet') or '').strip()

# plugins — may be a list of paths or a dict {path: name}
plugins_raw = d.get('plugins', [])
if isinstance(plugins_raw, dict):
    plugins = list(plugins_raw.keys())
elif isinstance(plugins_raw, list):
    plugins = [str(x) for x in plugins_raw if x]
else:
    plugins = []

# Emit shell-safe assignments
def sh(s):
    return "'" + str(s).replace("'", "'\\''") + "'"

print(f"ORIGINAL_PREFIX={sh(prefix)}")
print(f"ORIGINAL_URL={sh(url)}")
print(f"ORIGINAL_THEME={sh(theme)}")
print(f"ORIGINAL_PLUGINS_LIST={sh(chr(10).join(plugins))}")
PYEOF
)"
        echo -e "${GREEN}Archive metadata:${ENDCOLOR}"
        echo -e "  ${GREEN}Table prefix:${ENDCOLOR}  ${BOLDGREEN}${ORIGINAL_PREFIX}${ENDCOLOR}"
        [[ -n "$ORIGINAL_URL"   ]] && echo -e "  ${GREEN}Original URL:${ENDCOLOR}  ${YELLOW}${ORIGINAL_URL}${ENDCOLOR}"
        [[ -n "$ORIGINAL_THEME" ]] && echo -e "  ${GREEN}Active theme:${ENDCOLOR}  ${YELLOW}${ORIGINAL_THEME}${ENDCOLOR}"
        if [[ -n "$ORIGINAL_PLUGINS_LIST" ]]; then
            local plugin_count
            plugin_count=$(echo "$ORIGINAL_PLUGINS_LIST" | grep -c '.')
            echo -e "  ${GREEN}Plugins found:${ENDCOLOR} ${YELLOW}${plugin_count}${ENDCOLOR}"
        fi
    else
        echo -e "${YELLOW}package.json not found — using default prefix 'wp_', theme auto-detection${ENDCOLOR}"
    fi

    # Show prefix clearly. Only allow override with explicit double-confirmation
    # to prevent accidental mistyping (this caused issues in previous runs).
    echo -e "${SEPARATOR}"
    echo -e "${YELLOW}Table prefix to use: ${BOLDGREEN}${ORIGINAL_PREFIX}${ENDCOLOR}"
    echo -e "${YELLOW}Press Enter to confirm, or type a different prefix only if you are certain:${ENDCOLOR}"
    read -rp "> " PREFIX_OVERRIDE
    if [[ -n "$PREFIX_OVERRIDE" && "$PREFIX_OVERRIDE" != "$ORIGINAL_PREFIX" ]]; then
        echo -e "${RED}You typed '${PREFIX_OVERRIDE}' — this differs from the archive prefix '${ORIGINAL_PREFIX}'.${ENDCOLOR}"
        read -rp "> Are you sure you want to override? [y/n]: " CONFIRM_OVERRIDE
        [[ "${CONFIRM_OVERRIDE}" =~ ^[yY](es)?$ ]] \
            && ORIGINAL_PREFIX="$PREFIX_OVERRIDE" \
            && echo -e "${YELLOW}Prefix overridden to: ${ORIGINAL_PREFIX}${ENDCOLOR}" \
            || echo -e "${GREEN}Keeping original prefix: ${ORIGINAL_PREFIX}${ENDCOLOR}"
    fi

    echo -e "${SEPARATOR}"
}

# ─── Save activation data from SERVMASK_ tables before rename ─────────────────
# AI1WM intentionally blanks out active_plugins, template, and stylesheet in
# the SQL dump so its own restore UI can safely handle plugin/theme activation.
# We read these values from the SERVMASK_PREFIX_options table immediately after
# import (before rename) and use them in restore_wpress_activation().
save_wpress_activation_data() {
    echo -e "${BLUE}Reading activation data from backup DB...${ENDCOLOR}"

    local q_template q_stylesheet
    q_template="SELECT option_value FROM SERVMASK_PREFIX_options WHERE option_name='template' LIMIT 1;"
    q_stylesheet="SELECT option_value FROM SERVMASK_PREFIX_options WHERE option_name='stylesheet' LIMIT 1;"

    SAVED_TEMPLATE=$(mysql -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" 2>/dev/null -sN -e "$q_template" \
        | grep -v "Deprecated" | head -1)
    SAVED_STYLESHEET=$(mysql -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" 2>/dev/null -sN -e "$q_stylesheet" \
        | grep -v "Deprecated" | head -1)

    if [[ -n "$SAVED_TEMPLATE" ]]; then
        echo -e "  ${GREEN}Theme from DB dump:${ENDCOLOR}  ${YELLOW}${SAVED_TEMPLATE}${ENDCOLOR}"
    else
        echo -e "  ${YELLOW}Theme not found in DB dump (AI1WM cleared it) — will use package.json or filesystem${ENDCOLOR}"
    fi

    echo -e "${SEPARATOR}"
}

# ─── Drop all tables (clears fresh WP install before backup import) ───────────
drop_fresh_wp_tables() {
    echo -e "${BLUE}Dropping fresh WordPress tables before import...${ENDCOLOR}"

    local drop_sql
    drop_sql=$(mysql -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" 2>/dev/null -sN -e "
        SELECT CONCAT('DROP TABLE IF EXISTS \`', table_name, '\`;')
        FROM information_schema.tables
        WHERE table_schema = DATABASE();
    " | grep -v Deprecated)

    if [[ -n "$drop_sql" ]]; then
        echo "$drop_sql" | mysql -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" 2>/dev/null \
            && echo -e "${GREEN}Fresh tables dropped.${ENDCOLOR}" \
            || echo -e "${RED}Warning: some tables could not be dropped.${ENDCOLOR}"
    else
        echo -e "${YELLOW}No tables found — nothing to drop.${ENDCOLOR}"
    fi

    echo -e "${SEPARATOR}"
}

# ─── Import SQL ───────────────────────────────────────────────────────────────
restore_sql_dump() {
    local DUMP=""

    if [[ "${BACKUP_TYPE}" == "wpress" ]]; then
        [[ -z "$WPRESS_SQL" || ! -f "$WPRESS_SQL" ]] && err "database.sql not found after extraction."
        DUMP="$WPRESS_SQL"
        echo -e "Using SQL from archive: ${GREEN}${DUMP}${ENDCOLOR}"
    else
        local SQL_DUMPS=()
        while IFS= read -r -d $'\0' f; do SQL_DUMPS+=("$f"); done \
            < <(find . -maxdepth 1 -type f -name "*.sql" -print0)
        [[ "${#SQL_DUMPS[@]}" -eq 0 ]] && err "No .sql dumps found in ${PWD}"

        if [[ "${#SQL_DUMPS[@]}" -gt 1 ]]; then
            local NUM=1
            for i in "${SQL_DUMPS[@]}"; do echo "${NUM}. $i"; NUM=$((NUM+1)); done | column -t
            local DUMP_CHOICE
            read -rp "> Choose: " DUMP_CHOICE
            DUMP="${SQL_DUMPS[$((DUMP_CHOICE-1))]}"
        else
            DUMP="${SQL_DUMPS[0]}"; echo "$DUMP"
        fi

        local CHOICE
        read -rp "> Proceed? [y/n]: " CHOICE
        [[ ! "${CHOICE}" =~ ^[yY](es)?$ ]] && err "Ok, next time"
    fi

    echo -e "\n${BLUE}Importing $(basename "$DUMP") into ${DB_NAME}...${ENDCOLOR}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Importing $(basename "$DUMP") into $DB_NAME..." >> "$LOG_FILE"

    if mysql -f -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" < "$DUMP" >> "$LOG_FILE" 2>&1; then
        echo -e "${GREEN}Import successful.${ENDCOLOR}"
        echo "$(date '+%Y-%m-%d %H:%M:%S') - SQL imported successfully." >> "$LOG_FILE"
    else
        err "SQL import failed. Check $LOG_FILE."
    fi

    echo -e "${SEPARATOR}"
}

# ─── Fix SERVMASK_PREFIX_ placeholders left by AI1WM ─────────────────────────
# Step 1: rename SERVMASK_PREFIX_* tables → real prefix (direct SQL, no WP needed)
# Step 2: fix SERVMASK_PREFIX_ stored inside table data via wp search-replace
fix_wpress_database() {
    local orig_prefix="${ORIGINAL_PREFIX:-wp_}"

    echo -e "${BLUE}Step 1/2 — Renaming tables SERVMASK_PREFIX_ → ${orig_prefix}${ENDCOLOR}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Renaming SERVMASK_PREFIX_ → ${orig_prefix}" >> "$LOG_FILE"

    local rename_sql
    rename_sql=$(mysql -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" 2>/dev/null -sN -e "
        SELECT CONCAT(
            'RENAME TABLE \`', table_name, '\` TO \`',
            REPLACE(table_name, 'SERVMASK_PREFIX_', '${orig_prefix}'),
            '\`;'
        )
        FROM information_schema.tables
        WHERE table_schema = DATABASE()
          AND table_name LIKE 'SERVMASK_PREFIX_%';
    " | grep -v Deprecated)

    if [[ -z "$rename_sql" ]]; then
        echo -e "${YELLOW}No SERVMASK_PREFIX_ tables found — skipping rename.${ENDCOLOR}"
    else
        echo "$rename_sql" | mysql -u "$DB_NAME" -p"$DB_PASS" "$DB_NAME" 2>/dev/null \
            && echo -e "${GREEN}Tables renamed.${ENDCOLOR}" \
            || echo -e "${RED}Warning: some tables could not be renamed.${ENDCOLOR}"
    fi

    echo -e "${BLUE}Step 2/2 — Fixing SERVMASK_PREFIX_ inside table data...${ENDCOLOR}"
    if command -v wp &>/dev/null; then
        wp search-replace "SERVMASK_PREFIX_" "${orig_prefix}" \
            --all-tables --skip-plugins --skip-themes 2>/dev/null \
            && echo -e "${GREEN}Data fixed.${ENDCOLOR}" \
            || echo -e "${YELLOW}Warning: data search-replace may have partially failed.${ENDCOLOR}"
    else
        echo -e "${YELLOW}wp-cli not found — run manually:${ENDCOLOR}"
        echo -e "  wp search-replace 'SERVMASK_PREFIX_' '${orig_prefix}' --all-tables"
    fi

    echo "$(date '+%Y-%m-%d %H:%M:%S') - SERVMASK_PREFIX_ fix complete." >> "$LOG_FILE"
    echo -e "${SEPARATOR}"
}

# ─── Update $table_prefix in existing wp-config.php ──────────────────────────
update_wp_config_prefix() {
    local prefix="$1"
    if [[ -f "wp-config.php" ]]; then
        sed -i "s/\(\\\$table_prefix\s*=\s*\)'[^']*'/\1'${prefix}'/" wp-config.php \
            && echo -e "${GREEN}wp-config.php: prefix updated to '${prefix}'${ENDCOLOR}" \
            || echo -e "${RED}Could not update prefix in wp-config.php — set it manually.${ENDCOLOR}"
        chmod 600 wp-config.php
        echo "$(date '+%Y-%m-%d %H:%M:%S') - wp-config.php prefix → ${prefix}" >> "$LOG_FILE"
    fi
}

# ─── Generate wp-config.php from scratch ─────────────────────────────────────
generate_wp_config() {
    echo -e "${BLUE}Generating wp-config.php...${ENDCOLOR}"

    local PREFIX="${ORIGINAL_PREFIX:-wp_}"

    local OLD_CONFIG
    OLD_CONFIG=$(find . -maxdepth 1 -name "wp-config.php" | head -1)
    if [[ -n "$OLD_CONFIG" ]]; then
        mv "$OLD_CONFIG" "${OLD_CONFIG}.bak.$(date +%s)"
        echo -e "${YELLOW}Old wp-config.php backed up.${ENDCOLOR}"
    fi

    local KEYS
    KEYS=$(curl -s --max-time 10 https://api.wordpress.org/secret-key/1.1/salt/ 2>/dev/null || true)
    if [[ -z "$KEYS" ]]; then
        echo -e "${YELLOW}Could not fetch WP API keys — generating locally...${ENDCOLOR}"
        KEYS="define('AUTH_KEY',         '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('SECURE_AUTH_KEY',  '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('LOGGED_IN_KEY',    '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('NONCE_KEY',        '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('AUTH_SALT',        '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('SECURE_AUTH_SALT', '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('LOGGED_IN_SALT',   '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');
define('NONCE_SALT',       '$(tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' </dev/urandom | head -c 64)');"
    fi

    cat > wp-config.php <<PHP
<?php
define( 'DB_NAME',     '${DB_NAME}' );
define( 'DB_USER',     '${DB_NAME}' );
define( 'DB_PASSWORD', '${DB_PASS}' );
define( 'DB_HOST',     'localhost' );
define( 'DB_CHARSET',  'utf8mb4' );
define( 'DB_COLLATE',  '' );

${KEYS}

\$table_prefix = '${PREFIX}';

define( 'WP_DEBUG', false );

if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';
PHP

    chmod 600 wp-config.php
    echo -e "${BOLDGREEN}wp-config.php generated (prefix: ${PREFIX}).${ENDCOLOR}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - wp-config.php generated. DB: $DB_NAME, prefix: $PREFIX" >> "$LOG_FILE"
    echo -e "${SEPARATOR}"
}

extract_archive() {
    TAR_SAFE=$(tar --help 2>/dev/null | grep -q -- "--keep-old-files" && echo true)
    ZIP_SAFE=$(unzip --help 2>/dev/null | grep -q -- "\-n" && echo true)
    [[ -z "${TAR_SAFE}" || -z "${ZIP_SAFE}" ]] && err "tar or unzip failed safe check"

    if [[ "${BACKUP_TYPE}" == "targz" ]]; then
        tar -tzf "${BACKUP}" >> "$LOG_FILE" 2>&1 || err "Archive ${BACKUP} is corrupted."
        tar --keep-old-files -zxvf "${BACKUP}" >> "$LOG_FILE" 2>&1 \
            && echo -e "${GREEN}${BACKUP} restored!${ENDCOLOR}" \
            || err "Extraction failed."
    elif [[ "${BACKUP_TYPE}" == "zip" ]]; then
        unzip -t "${BACKUP}" >> "$LOG_FILE" 2>&1 || err "Archive ${BACKUP} is corrupted."
        unzip -n "${BACKUP}" >> "$LOG_FILE" 2>&1 \
            && echo -e "${GREEN}${BACKUP} restored!${ENDCOLOR}" \
            || err "Extraction failed."
    fi
    echo -e "${SEPARATOR}"
}

# ─── Restore theme and plugin activation ─────────────────────────────────────
# AI1WM intentionally clears active_plugins, template, and stylesheet in the
# SQL dump so its own restore UI can safely handle activation. When we restore
# via direct SQL import, these options come up empty.
#
# Priority for theme selection:
#   1. Value saved from SERVMASK_PREFIX_options before rename (most accurate)
#   2. 'theme' field from package.json
#   3. Non-default theme folder found on disk (last resort)
#
# Plugins are always activated from package.json list if available,
# otherwise wp plugin activate --all is used.
restore_wpress_activation() {
    echo -e "${BLUE}Restoring theme and plugin activation...${ENDCOLOR}"

    if ! command -v wp &>/dev/null; then
        echo -e "${YELLOW}wp-cli not found — activate theme and plugins manually.${ENDCOLOR}"
        echo -e "${SEPARATOR}"
        return
    fi

    # ── Theme ─────────────────────────────────────────────────────────────────
    local current_theme
    current_theme=$(wp option get template 2>/dev/null | grep -v Deprecated)

    if [[ -z "$current_theme" ]]; then
        # Determine which theme to activate
        local theme_to_activate="${SAVED_TEMPLATE:-$ORIGINAL_THEME}"

        if [[ -z "$theme_to_activate" ]]; then
            # Fallback: scan filesystem, skip bundled WP default themes
            theme_to_activate=$(ls wp-content/themes/ 2>/dev/null \
                | grep -v "^index\.php$" \
                | grep -Ev "^twentytwenty(one|two|three|four|five|six)?$" \
                | head -1)
        fi

        if [[ -n "$theme_to_activate" ]]; then
            echo -e "${BLUE}Activating theme: ${YELLOW}${theme_to_activate}${ENDCOLOR}"
            if wp theme activate "$theme_to_activate" 2>/dev/null; then
                echo -e "${GREEN}Theme activated: ${theme_to_activate}${ENDCOLOR}"
                echo "$(date '+%Y-%m-%d %H:%M:%S') - Theme activated: ${theme_to_activate}" >> "$LOG_FILE"
                # Also set stylesheet if we have it
                local stylesheet="${SAVED_STYLESHEET:-$theme_to_activate}"
                [[ "$stylesheet" != "$theme_to_activate" ]] && \
                    wp option update stylesheet "$stylesheet" 2>/dev/null
            else
                echo -e "${RED}Could not activate '${theme_to_activate}' — activate manually:${ENDCOLOR}"
                echo -e "  wp theme activate ${theme_to_activate}"
            fi
        else
            echo -e "${YELLOW}No custom theme detected. Available themes:${ENDCOLOR}"
            wp theme list 2>/dev/null | grep -v Deprecated
            echo -e "${YELLOW}Activate manually: wp theme activate <theme-name>${ENDCOLOR}"
        fi
    else
        echo -e "${GREEN}Theme already set: ${current_theme}${ENDCOLOR}"
    fi

    # ── Plugins ───────────────────────────────────────────────────────────────
    local active_count
    active_count=$(wp plugin list --status=active --format=count 2>/dev/null \
        | grep -v Deprecated || echo 0)

    if [[ "${active_count:-0}" -eq 0 ]]; then
        echo -e "${BLUE}Activating plugins...${ENDCOLOR}"

        if [[ -n "$ORIGINAL_PLUGINS_LIST" ]]; then
            # Activate the exact plugins listed in package.json
            local ok=0 fail=0
            while IFS= read -r plugin_path; do
                [[ -z "$plugin_path" ]] && continue
                if wp plugin activate "$plugin_path" 2>/dev/null; then
                    ok=$((ok+1))
                else
                    echo -e "  ${YELLOW}Could not activate: ${plugin_path}${ENDCOLOR}"
                    fail=$((fail+1))
                fi
            done <<< "$ORIGINAL_PLUGINS_LIST"
            echo -e "${GREEN}Plugins: ${ok} activated, ${fail} skipped.${ENDCOLOR}"
        else
            # No list from package.json — activate everything installed
            wp plugin activate --all 2>/dev/null \
                && echo -e "${GREEN}All plugins activated.${ENDCOLOR}" \
                || echo -e "${YELLOW}Some plugins could not be activated.${ENDCOLOR}"
        fi

        echo "$(date '+%Y-%m-%d %H:%M:%S') - Plugin activation complete." >> "$LOG_FILE"
    else
        echo -e "${GREEN}Plugins already active: ${active_count}${ENDCOLOR}"
    fi

    echo -e "${SEPARATOR}"
}

# ─── Optional URL search-replace ─────────────────────────────────────────────
offer_url_replace() {
    echo -e "${YELLOW}URL update (optional)${ENDCOLOR}"
    if [[ -n "$ORIGINAL_URL" ]]; then
        echo -e "  Original URL from archive: ${BLUE}${ORIGINAL_URL}${ENDCOLOR}"
    fi
    read -rp "> Enter new site URL (e.g. https://newdomain.com) or Enter to skip: " NEW_URL

    if [[ -z "$NEW_URL" ]]; then
        echo -e "${YELLOW}Skipping URL replacement.${ENDCOLOR}"
        echo -e "${SEPARATOR}"
        return
    fi

    if command -v wp &>/dev/null; then
        if [[ -n "$ORIGINAL_URL" && "$NEW_URL" != "$ORIGINAL_URL" ]]; then
            echo -e "${BLUE}Replacing ${ORIGINAL_URL} → ${NEW_URL}${ENDCOLOR}"
            wp search-replace "$ORIGINAL_URL" "$NEW_URL" \
                --all-tables --skip-plugins --skip-themes 2>/dev/null \
                && echo -e "${GREEN}URLs replaced.${ENDCOLOR}" \
                || echo -e "${YELLOW}Warning: URL replacement may have partially failed.${ENDCOLOR}"
        fi
        wp option update siteurl "$NEW_URL" 2>/dev/null
        wp option update home    "$NEW_URL" 2>/dev/null
        wp rewrite flush         2>/dev/null
        echo -e "${GREEN}siteurl, home, and rewrite rules updated.${ENDCOLOR}"
    else
        echo -e "${YELLOW}wp-cli not found — update URL manually:${ENDCOLOR}"
        echo -e "  wp search-replace '${ORIGINAL_URL}' '${NEW_URL}' --all-tables"
    fi

    echo "$(date '+%Y-%m-%d %H:%M:%S') - URL updated → ${NEW_URL}" >> "$LOG_FILE"
    echo -e "${SEPARATOR}"
}

# ─── Main ─────────────────────────────────────────────────────────────────────
echo -e "                         ${BOLDGREEN}Hello fellow concierge!${ENDCOLOR}\n"
check_user
check_home_directory

find_backup

# ── .wpress flow ──────────────────────────────────────────────────────────────
if [[ "${BACKUP_TYPE}" == "wpress" ]]; then

    if [[ ! -f "${PWD}/wp-config.php" ]]; then
        echo -e "${YELLOW}No WordPress installation found in ${PWD}.${ENDCOLOR}"
        echo -e "${BLUE}NOTE: .wpress backups contain only wp-content — WP core files${ENDCOLOR}"
        echo -e "${BLUE}(wp-admin/, wp-includes/, etc.) are needed separately.${ENDCOLOR}"
        read -rp "> Install fresh WordPress here before restoring? [y/n]: " INSTALL_CHOICE

        if [[ "${INSTALL_CHOICE}" =~ ^[yY](es)?$ ]]; then
            install_fresh_wp
        else
            echo -e "${YELLOW}Proceeding without fresh install.${ENDCOLOR}"
            show_disclaimer
            backup_unwanted_files
        fi
    else
        echo -e "${YELLOW}Existing WordPress installation detected.${ENDCOLOR}"
        echo -e "  ${BLUE}wp-content/ will be overwritten from the backup${ENDCOLOR}"
        echo -e "  ${BLUE}A new database will be created and backup DB imported${ENDCOLOR}"
        echo -e "  ${BLUE}WP core files (wp-admin/, wp-includes/) will NOT be changed${ENDCOLOR}"
        read -rp "> Proceed? [y/n]: " CHOICE
        [[ ! "${CHOICE}" =~ ^[yY](es)?$ ]] && err "Aborted."
    fi

    # Extract: package.json + database.sql → WP root; everything else → wp-content/
    extract_wpress

    # Read prefix, URL, theme, plugin list from package.json
    read_wpress_metadata

    if [[ "$FRESH_INSTALL" == "true" ]]; then
        drop_fresh_wp_tables
        restore_sql_dump
        save_wpress_activation_data        # read template/stylesheet from SERVMASK_ table
        update_wp_config_prefix "$ORIGINAL_PREFIX"
    else
        create_database
        restore_sql_dump
        save_wpress_activation_data        # read template/stylesheet from SERVMASK_ table
        generate_wp_config
    fi

    fix_wpress_database                    # rename tables + fix data
    restore_wpress_activation              # activate theme and plugins
    offer_url_replace

# ── .tar.gz / .zip flow ───────────────────────────────────────────────────────
else
    show_disclaimer
    backup_unwanted_files
    extract_archive
    create_database
    restore_sql_dump
    generate_wp_config
fi

# ─── Done ─────────────────────────────────────────────────────────────────────
echo -e "\n${BOLDGREEN}Restoration complete!${ENDCOLOR}"
echo -e "Next steps:"
echo -e "  1. ${YELLOW}Delete${ENDCOLOR} $LOG_FILE — it contains DB credentials"
echo -e "  2. ${YELLOW}Flush cache${ENDCOLOR} if any caching plugin is active:"
echo -e "     wp cache flush"
echo -e "  3. ${YELLOW}Update URLs${ENDCOLOR} if domain changed and you skipped the prompt above:"
echo -e "     wp search-replace 'https://old.com' 'https://new.com' --all-tables"
