#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)
ROOT_DIR=$(cd -- "${SCRIPT_DIR}/../.." && pwd)
EXAMPLE_FILE="${SCRIPT_DIR}/.env.example"
DEFAULT_TARGET_FILE="${SCRIPT_DIR}/.env"
TARGET_FILE="${1:-${DEFAULT_TARGET_FILE}}"
COMPOSE_FILE="${ROOT_DIR}/compose.prod.yaml"

if [ ! -f "${EXAMPLE_FILE}" ]; then
    echo "Missing template: ${EXAMPLE_FILE}" >&2
    exit 1
fi

if ! command -v openssl >/dev/null 2>&1; then
    echo "openssl is required." >&2
    exit 1
fi

command_exists() {
    command -v "$1" >/dev/null 2>&1
}

load_existing_env() {
    if [ -f "${TARGET_FILE}" ]; then
        set -a
        # shellcheck disable=SC1090
        . "${TARGET_FILE}"
        set +a
    fi
}

generate_uuid() {
    if command_exists uuidgen; then
        uuidgen | tr '[:upper:]' '[:lower:]'
        return
    fi

    if [ -r /proc/sys/kernel/random/uuid ]; then
        tr '[:upper:]' '[:lower:]' < /proc/sys/kernel/random/uuid
        return
    fi

    openssl rand -hex 16 | sed -E 's/(.{8})(.{4})(.{4})(.{4})(.{12})/\1-\2-\3-\4-\5/'
}

generate_secret() {
    openssl rand -hex "${1}"
}

detect_public_ipv4() {
    if ! command_exists curl; then
        return 0
    fi

    for url in \
        "https://api.ipify.org" \
        "https://ifconfig.me/ip"
    do
        ip=$(curl -fsSL --max-time 3 "${url}" 2>/dev/null || true)
        if printf '%s' "${ip}" | grep -Eq '^[0-9]{1,3}(\.[0-9]{1,3}){3}$'; then
            printf '%s\n' "${ip}"
            return 0
        fi
    done
}

prompt() {
    local prompt_text="${1}"
    local default_value="${2:-}"
    local answer

    if [ -n "${default_value}" ]; then
        printf "%s [%s]: " "${prompt_text}" "${default_value}" >&2
    else
        printf "%s: " "${prompt_text}" >&2
    fi

    IFS= read -r answer
    if [ -z "${answer}" ]; then
        printf '%s\n' "${default_value}"
    else
        printf '%s\n' "${answer}"
    fi
}

prompt_required() {
    local prompt_text="${1}"
    local default_value="${2:-}"
    local value

    while true; do
        value=$(prompt "${prompt_text}" "${default_value}")
        if [ -n "${value}" ]; then
            printf '%s\n' "${value}"
            return 0
        fi
        echo "This value is required." >&2
    done
}

prompt_yes_no() {
    local prompt_text="${1}"
    local default_answer="${2:-y}"
    local suffix="[Y/n]"

    if [ "${default_answer}" = "n" ]; then
        suffix="[y/N]"
    fi

    while true; do
        printf "%s %s: " "${prompt_text}" "${suffix}"
        IFS= read -r answer
        answer=${answer:-${default_answer}}

        case "${answer}" in
            y|Y|yes|YES)
                return 0
                ;;
            n|N|no|NO)
                return 1
                ;;
        esac

        echo "Please answer y or n."
    done
}

sanitize_database_suffix() {
    printf '%s' "${1}" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/_/g; s/^_+//; s/_+$//'
}

escape_regex() {
    printf '%s' "${1}" | sed -E 's/[][(){}.^$*+?|\\-]/\\&/g'
}

write_env_file() {
    cat > "${TARGET_FILE}" <<EOF
APP_DOMAIN=${APP_DOMAIN}
PUBLIC_BASE_DOMAIN=${PUBLIC_BASE_DOMAIN}

TENANT_ID=${TENANT_ID}
TENANT_SUBDOMAIN=${TENANT_SUBDOMAIN}
MASTER_DATABASE_NAME=${MASTER_DATABASE_NAME}
TENANT_DATABASE_NAME=${TENANT_DATABASE_NAME}
POSTGRES_USER=${POSTGRES_USER}
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

APP_SECRET=${APP_SECRET}
JWT_PASSPHRASE=${JWT_PASSPHRASE}

TRUSTED_PROXIES='${TRUSTED_PROXIES}'
TRUSTED_HOSTS='${TRUSTED_HOSTS}'
CORS_ALLOW_ORIGIN='${CORS_ALLOW_ORIGIN}'

MAILER_DSN=${MAILER_DSN}
ADMIN_ALERT_EMAIL=${ADMIN_ALERT_EMAIL}

TURNSTILE_SECRET_KEY=${TURNSTILE_SECRET_KEY}
TURNSTILE_FAIL_OPEN=${TURNSTILE_FAIL_OPEN}
PUBLIC_TURNSTILE_SITE_KEY=${PUBLIC_TURNSTILE_SITE_KEY}

SENTRY_DSN=${SENTRY_DSN}
SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}
EOF
}

validate_compose_config() {
    if ! command_exists docker; then
        echo "docker not found, skipping compose validation."
        return 0
    fi

    if [ ! -f "${COMPOSE_FILE}" ]; then
        echo "compose.prod.yaml not found, skipping compose validation."
        return 0
    fi

    if docker compose --env-file "${TARGET_FILE}" -f "${COMPOSE_FILE}" config >/dev/null; then
        echo "docker compose validation: OK"
        return 0
    fi

    echo "docker compose validation failed." >&2
    return 1
}

load_existing_env

echo "Classeo VPS env generator"
echo

PUBLIC_IP_DEFAULT=${PUBLIC_IP:-$(detect_public_ipv4 || true)}
if [ -n "${PUBLIC_IP_DEFAULT}" ]; then
    echo "Detected public IPv4: ${PUBLIC_IP_DEFAULT}"
    echo
fi

DEFAULT_BASE_DOMAIN=${PUBLIC_BASE_DOMAIN:-example.com}
PUBLIC_BASE_DOMAIN=$(prompt_required "Base domain" "${DEFAULT_BASE_DOMAIN}")

DEFAULT_TENANT_SUBDOMAIN=${TENANT_SUBDOMAIN:-demo}
TENANT_SUBDOMAIN=$(prompt_required "Tenant subdomain" "${DEFAULT_TENANT_SUBDOMAIN}")

DEFAULT_APP_DOMAIN=${APP_DOMAIN:-${TENANT_SUBDOMAIN}.${PUBLIC_BASE_DOMAIN}}
APP_DOMAIN=$(prompt_required "Full application domain" "${DEFAULT_APP_DOMAIN}")

DEFAULT_ADMIN_ALERT_EMAIL=${ADMIN_ALERT_EMAIL:-admin@${PUBLIC_BASE_DOMAIN}}
ADMIN_ALERT_EMAIL=$(prompt_required "Admin alert email" "${DEFAULT_ADMIN_ALERT_EMAIL}")

DEFAULT_POSTGRES_USER=${POSTGRES_USER:-classeo}
POSTGRES_USER=$(prompt_required "PostgreSQL user" "${DEFAULT_POSTGRES_USER}")

DEFAULT_MASTER_DATABASE_NAME=${MASTER_DATABASE_NAME:-classeo_master}
MASTER_DATABASE_NAME=$(prompt_required "Master database name" "${DEFAULT_MASTER_DATABASE_NAME}")

DEFAULT_TENANT_ID=${TENANT_ID:-$(generate_uuid)}
TENANT_ID=$(prompt_required "Tenant UUID" "${DEFAULT_TENANT_ID}")

DATABASE_SUFFIX=$(sanitize_database_suffix "${TENANT_SUBDOMAIN}")
DEFAULT_TENANT_DATABASE_NAME=${TENANT_DATABASE_NAME:-classeo_tenant_${DATABASE_SUFFIX}}
TENANT_DATABASE_NAME=$(prompt_required "Tenant database name" "${DEFAULT_TENANT_DATABASE_NAME}")

DEFAULT_MAILER_DSN=${MAILER_DSN:-null://null}
MAILER_DSN=$(prompt_required "Mailer DSN" "${DEFAULT_MAILER_DSN}")

DEFAULT_SENTRY_DSN=${SENTRY_DSN:-}
SENTRY_DSN=$(prompt "Sentry DSN (optional)" "${DEFAULT_SENTRY_DSN}")

if prompt_yes_no "Use Cloudflare Turnstile test keys" "y"; then
    TURNSTILE_SECRET_KEY="1x0000000000000000000000000000000AA"
    TURNSTILE_FAIL_OPEN="true"
    PUBLIC_TURNSTILE_SITE_KEY="1x00000000000000000000AA"
else
    TURNSTILE_SECRET_KEY=$(prompt_required "Turnstile secret key" "${TURNSTILE_SECRET_KEY:-}")
    TURNSTILE_FAIL_OPEN=$(prompt_required "Turnstile fail open (true/false)" "${TURNSTILE_FAIL_OPEN:-false}")
    PUBLIC_TURNSTILE_SITE_KEY=$(prompt_required "Turnstile site key" "${PUBLIC_TURNSTILE_SITE_KEY:-}")
fi

TRUSTED_PROXIES=${TRUSTED_PROXIES:-127.0.0.1/32,172.16.0.0/12}
ESCAPED_BASE_DOMAIN=$(escape_regex "${PUBLIC_BASE_DOMAIN}")
TRUSTED_HOSTS="^(.+\\.)?${ESCAPED_BASE_DOMAIN}\$"
CORS_ALLOW_ORIGIN="^https://([\\w-]+\\.)?${ESCAPED_BASE_DOMAIN}\$"
POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-$(generate_secret 16)}
APP_SECRET=${APP_SECRET:-$(generate_secret 32)}
JWT_PASSPHRASE=${JWT_PASSPHRASE:-$(generate_secret 24)}
SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-production}

echo
echo "Summary"
echo "- App domain: ${APP_DOMAIN}"
echo "- Base domain: ${PUBLIC_BASE_DOMAIN}"
echo "- Tenant subdomain: ${TENANT_SUBDOMAIN}"
echo "- Tenant UUID: ${TENANT_ID}"
echo "- Target file: ${TARGET_FILE}"
if [ -n "${PUBLIC_IP_DEFAULT}" ]; then
    echo "- Public IPv4: ${PUBLIC_IP_DEFAULT}"
fi
echo

if ! prompt_yes_no "Write ${TARGET_FILE}" "y"; then
    echo "Aborted."
    exit 1
fi

mkdir -p "$(dirname "${TARGET_FILE}")"

if [ -f "${TARGET_FILE}" ]; then
    cp "${TARGET_FILE}" "${TARGET_FILE}.bak"
    echo "Backup created: ${TARGET_FILE}.bak"
fi

write_env_file
echo "Generated ${TARGET_FILE}"

validate_compose_config

echo
echo "Next steps:"
echo "1. Review ${TARGET_FILE}"
echo "2. Run ./deploy/vps/generate-jwt.sh"
echo "3. Run docker compose --env-file ${TARGET_FILE} -f compose.prod.yaml up -d --build"
