#!/usr/bin/env bash

set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TIMESTAMP="$(date +"%Y%m%d-%H%M%S")"
BACKUP_ROOT="$ROOT_DIR/storage/app/backups/$TIMESTAMP"
TEMP_DB_DIR="$BACKUP_ROOT/database"
CODE_ZIP="$BACKUP_ROOT/codigo-repositorio-$TIMESTAMP.zip"
MEDIA_ZIP="$BACKUP_ROOT/media-original-$TIMESTAMP.zip"
DB_SQL="$TEMP_DB_DIR/base-de-datos-$TIMESTAMP.sql"
DB_ZIP="$BACKUP_ROOT/base-de-datos-$TIMESTAMP.zip"
MANIFEST="$BACKUP_ROOT/SHA256SUMS.txt"

read_env() {
    local key="$1"
    local value

    value="$(grep -E "^${key}=" "$ROOT_DIR/.env" | head -n 1 | cut -d '=' -f 2- || true)"
    value="${value%\"}"
    value="${value#\"}"

    printf '%s' "$value"
}

require_command() {
    if ! command -v "$1" >/dev/null 2>&1; then
        printf 'Falta el comando requerido: %s\n' "$1" >&2
        exit 1
    fi
}

zip_if_exists() {
    local output="$1"
    shift

    local existing=()
    local path
    for path in "$@"; do
        if [ -e "$ROOT_DIR/$path" ]; then
            existing+=("$path")
        fi
    done

    if [ "${#existing[@]}" -eq 0 ]; then
        printf 'No hay rutas para %s, se omite.\n' "$output"
        return 1
    fi

    (
        cd "$ROOT_DIR"
        zip -r -q "$output" "${existing[@]}"
    )
}

require_command zip
require_command mysqldump

mkdir -p "$TEMP_DB_DIR"

DB_HOST="$(read_env DB_HOST)"
DB_PORT="$(read_env DB_PORT)"
DB_DATABASE="$(read_env DB_DATABASE)"
DB_USERNAME="$(read_env DB_USERNAME)"
DB_PASSWORD="$(read_env DB_PASSWORD)"

printf 'Creando respaldo en %s\n' "$BACKUP_ROOT"

printf '1/4 Exportando base de datos...\n'
if [ -n "$DB_PASSWORD" ]; then
    MYSQL_PWD="$DB_PASSWORD" mysqldump \
        --host="$DB_HOST" \
        --port="$DB_PORT" \
        --user="$DB_USERNAME" \
        --single-transaction \
        --skip-lock-tables \
        "$DB_DATABASE" > "$DB_SQL"
else
    mysqldump \
        --host="$DB_HOST" \
        --port="$DB_PORT" \
        --user="$DB_USERNAME" \
        --single-transaction \
        --skip-lock-tables \
        "$DB_DATABASE" > "$DB_SQL"
fi

printf '2/4 Empaquetando codigo limpio...\n'
(
    cd "$ROOT_DIR"
    zip -r -q "$CODE_ZIP" . \
        -x '.git/*' \
        -x 'node_modules/*' \
        -x 'vendor/*' \
        -x 'public/build/*' \
        -x 'storage/framework/*' \
        -x 'storage/logs/*' \
        -x 'storage/app/backups/*' \
        -x 'storage/app/course-media/*' \
        -x 'storage/app/course-imports/*' \
        -x 'storage/app/notion_probe/*' \
        -x 'curso/*' \
        -x 'database/backups/*' \
        -x '.env' \
        -x '.DS_Store'
)

printf '3/4 Empaquetando media original...\n'
MEDIA_CREATED=0
if zip_if_exists "$MEDIA_ZIP" \
    "curso" \
    "storage/app/course-media" \
    "storage/app/course-imports"; then
    MEDIA_CREATED=1
fi

printf '4/4 Empaquetando dump SQL y calculando hashes...\n'
(
    cd "$TEMP_DB_DIR"
    zip -r -q "$DB_ZIP" "$(basename "$DB_SQL")"
)

(
    cd "$BACKUP_ROOT"
    files=(
        "$(basename "$CODE_ZIP")"
        "$(basename "$DB_ZIP")"
    )

    if [ "$MEDIA_CREATED" -eq 1 ]; then
        files+=("$(basename "$MEDIA_ZIP")")
    fi

    shasum -a 256 "${files[@]}" > "$MANIFEST"
)

rm -rf "$TEMP_DB_DIR"

printf '\nRespaldo completado.\n'
printf 'Codigo: %s\n' "$CODE_ZIP"
if [ "$MEDIA_CREATED" -eq 1 ]; then
    printf 'Media:  %s\n' "$MEDIA_ZIP"
else
    printf 'Media:  no generada\n'
fi
printf 'DB:     %s\n' "$DB_ZIP"
printf 'Hashes: %s\n' "$MANIFEST"
