#!/usr/bin/env bash
# Enable HTTPS for the Apache vhost generated by the PrestaShop Debian 13 TUI.
# Generates a local CA and a hostname-specific server certificate. Does NOT
# contact Cloudflare, change the tunnel, or modify PrestaShop's database.
set -euo pipefail

[[ ${EUID} -eq 0 ]] || { echo 'Run as root: bash prestashop-enable-local-https.sh' >&2; exit 1; }
for cmd in openssl awk apache2ctl a2enmod a2ensite a2dissite systemctl; do
  command -v "$cmd" >/dev/null || { echo "Missing command: $cmd" >&2; exit 1; }
done

shopt -s nullglob
all_sites=(/etc/apache2/sites-available/ps-*.conf)
sites=()
for site in "${all_sites[@]}"; do
  [[ "$site" == *-ssl.conf ]] || sites+=("$site")
done
((${#sites[@]} > 0)) || { echo 'No ps-*.conf Apache site found. Check /etc/apache2/sites-available.' >&2; exit 1; }

if ((${#sites[@]} == 1)); then
  selected_site=${sites[0]}
else
  echo 'Choose the HTTP PrestaShop site to enable HTTPS for:'
  select chosen_site in "${sites[@]}"; do
    [[ -n ${chosen_site:-} ]] && { selected_site=$chosen_site; break; }
    echo 'Invalid selection.'
  done
fi

printf 'Apache HTTP site: %s\n' "$selected_site"
original_hostname=$(awk '$1 == "ServerName" {print $2; exit}' "$selected_site")
read -r -p "Public HTTPS hostname [${original_hostname:-shop.example.com}]: " hostname
hostname=${hostname:-$original_hostname}
hostname=${hostname,,}
if [[ ! $hostname =~ ^([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,63}$ || $hostname == *..* || ${#hostname} -gt 253 ]]; then
  echo "Invalid DNS hostname: $hostname" >&2; exit 1
fi

ssl_site="${selected_site%.conf}-ssl.conf"
[[ ! -e $ssl_site ]] || { echo "SSL virtual host already exists: $ssl_site; no changes made." >&2; exit 1; }
[[ $(grep -Ec '^[[:space:]]*<VirtualHost[[:space:]]+\*:80[[:space:]]*>[[:space:]]*$' "$selected_site") -eq 1 ]] || {
  echo "Expected exactly one <VirtualHost *:80> in $selected_site; no changes made." >&2; exit 1;
}

cert_dir=/etc/ssl/prestashop
ca_key="$cert_dir/local-ca.key"
ca_cert="$cert_dir/local-ca.crt"
server_key="$cert_dir/${hostname}.key"
server_cert="$cert_dir/${hostname}.crt"
public_ca=/etc/ssl/certs/prestashop-tunnel-ca.crt

printf '\nThis will:\n'
printf '  Generate a private CA and TLS certificate for %s\n' "$hostname"
printf '  Create %s and enable Apache HTTPS on port 443\n' "$ssl_site"
printf '  Keep the HTTP site and PrestaShop database unchanged\n'
read -r -p 'Proceed? [y/N] ' answer
[[ $answer == [yY] || $answer == [yY][eE][sS] ]] || { echo 'Cancelled.'; exit 0; }

install -d -m 0700 "$cert_dir"
umask 077
if [[ ! -e $ca_key && ! -e $ca_cert ]]; then
  echo 'Generating local private CA...'
  openssl req -new -x509 -nodes -sha256 -days 3650 -newkey rsa:3072 \
    -keyout "$ca_key" -out "$ca_cert" -subj '/CN=PrestaShop Tunnel Local CA' \
    -addext 'basicConstraints=critical,CA:TRUE,pathlen:0' \
    -addext 'keyUsage=critical,keyCertSign,cRLSign' >/dev/null 2>&1
elif [[ ! -f $ca_key || ! -f $ca_cert ]]; then
  echo "Incomplete CA files in $cert_dir; refusing to overwrite." >&2; exit 1
fi

if [[ ! -e $server_key && ! -e $server_cert ]]; then
  echo "Generating HTTPS certificate for $hostname..."
  temp_dir=$(mktemp -d)
  trap 'rm -rf -- "${temp_dir:-}"' EXIT
  openssl req -new -nodes -newkey rsa:2048 -sha256 \
    -keyout "$server_key" -out "$temp_dir/server.csr" -subj "/CN=$hostname" >/dev/null 2>&1
  cat > "$temp_dir/server.ext" <<EOF
basicConstraints=critical,CA:FALSE
keyUsage=critical,digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=DNS:$hostname
EOF
  openssl x509 -req -sha256 -days 365 -in "$temp_dir/server.csr" \
    -CA "$ca_cert" -CAkey "$ca_key" -CAcreateserial \
    -out "$server_cert" -extfile "$temp_dir/server.ext" >/dev/null 2>&1
elif [[ ! -f $server_key || ! -f $server_cert ]]; then
  echo "Incomplete certificate files for $hostname; refusing to overwrite." >&2; exit 1
fi

chmod 600 "$ca_key" "$server_key"
chmod 644 "$ca_cert" "$server_cert"
openssl verify -CAfile "$ca_cert" -verify_hostname "$hostname" "$server_cert"
install -m 0644 "$ca_cert" "$public_ca"

# Reproduce the existing FPM/DocumentRoot/Directory/Rewrite settings in SSL vhost.
tmp_conf=$(mktemp)
trap 'rm -f -- "${tmp_conf:-}"; rm -rf -- "${temp_dir:-}"' EXIT
if ! awk -v host="$hostname" -v cert="$server_cert" -v key="$server_key" '
  /^[[:space:]]*<VirtualHost[[:space:]]+\*:80[[:space:]]*>[[:space:]]*$/ {
    sub(/\*:80/, "*:443")
    print
    print "    ServerName " host
    print "    SSLEngine on"
    print "    SSLCertificateFile " cert
    print "    SSLCertificateKeyFile " key
    count++
    next
  }
  /^[[:space:]]*ServerName[[:space:]]/ { next }
  { print }
  END { if (count != 1) exit 1 }
' "$selected_site" > "$tmp_conf"; then
  echo 'Could not generate SSL virtual host.' >&2; exit 1
fi
install -m 0644 "$tmp_conf" "$ssl_site"
a2enmod ssl >/dev/null
a2ensite "$(basename "$ssl_site")" >/dev/null
if ! apache2ctl configtest; then
  a2dissite "$(basename "$ssl_site")" >/dev/null || true
  echo 'Apache configtest failed. SSL vhost disabled; HTTP remains available.' >&2
  exit 1
fi
if ! systemctl reload apache2; then
  a2dissite "$(basename "$ssl_site")" >/dev/null || true
  apache2ctl configtest || true
  systemctl reload apache2 || true
  echo 'Apache reload failed. SSL vhost disabled; check the service logs.' >&2
  exit 1
fi

printf '\nApache HTTPS enabled. Local CA (public certificate): %s\n' "$public_ca"
printf 'Certificate hostname: %s\n' "$hostname"
printf 'TLS test (on TP-CMS):\n  curl --cacert %s --resolve %s:443:127.0.0.1 -I https://%s/\n' "$public_ca" "$hostname" "$hostname"
printf '\nCloudflare Tunnel needs Service URL https://<TP-CMS-IP>:443, Origin Server Name %s, and CA Pool pointing to a COPY of %s on the cloudflared machine. Keep TLS verification ENABLED.\n' "$hostname" "$public_ca"
printf 'Once the tunnel works, enable SSL in PrestaShop Back Office (Shop Parameters > General).\n'
