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

# Deploy Microweber under /mw for a site (Laravel root: <site>/private/mw, web: <site>/public/mw).
#
# Usage:
#   bash deploy_microweber_subdir.sh \
#     --site-root /srv/www/client/draytonlogistics \
#     --app-url 'https://draytonlogistics.work/mw' \
#     --app-brand 'Drayton Logistics' \
#     --db-name draytonlogistics_mw \
#     --db-user drayton \
#     --db-pass 'secret' \
#     --cms-bridge-config /srv/www/client/draytonlogistics/private/app/config.local.php \
#     --cms-sso-secret 'hexsecret'

SOURCE="${MICROWEBER_SOURCE:-/srv/www/seethruit/CMS2/microweber}"

SITE_ROOT=""
APP_URL=""
APP_BRAND=""
DB_NAME=""
DB_USER=""
DB_PASS=""
CMS_BRIDGE=""
CMS_SSO=""
USE_SQLITE="0"
HOMEPAGE_URL=""
MW_AT_ROOT="0"
PUBLISH_TO_PARTIAL="0"

while (($#)); do
  case "$1" in
    --site-root) SITE_ROOT="${2:-}"; shift 2 ;;
    --app-url) APP_URL="${2:-}"; shift 2 ;;
    --app-brand) APP_BRAND="${2:-}"; shift 2 ;;
    --db-name) DB_NAME="${2:-}"; shift 2 ;;
    --db-user) DB_USER="${2:-}"; shift 2 ;;
    --db-pass) DB_PASS="${2:-}"; shift 2 ;;
    --cms-bridge-config) CMS_BRIDGE="${2:-}"; shift 2 ;;
    --cms-sso-secret) CMS_SSO="${2:-}"; shift 2 ;;
    --sqlite) USE_SQLITE="1"; shift ;;
    --homepage-url) HOMEPAGE_URL="${2:-}"; shift 2 ;;
    --mw-at-root) MW_AT_ROOT="1"; shift ;;
    --publish-to-partial) PUBLISH_TO_PARTIAL="1"; shift ;;
    *) echo "Unknown arg: $1" >&2; exit 1 ;;
  esac
done

if [[ -z "$SITE_ROOT" || ! -d "$SITE_ROOT/public" ]]; then
  echo "Error: --site-root must point to a directory containing public/" >&2
  exit 1
fi
if [[ -z "$APP_URL" || -z "$APP_BRAND" || -z "$CMS_BRIDGE" || -z "$CMS_SSO" ]]; then
  echo "Error: missing required flags (see script header)." >&2
  exit 1
fi
if [[ "$USE_SQLITE" != "1" ]]; then
  if [[ -z "$DB_NAME" || -z "$DB_USER" ]]; then
    echo "Error: --db-name and --db-user required unless --sqlite." >&2
    exit 1
  fi
fi

if [[ ! -f "$SOURCE/vendor/autoload.php" ]]; then
  echo "Error: run 'composer install' in $SOURCE first." >&2
  exit 1
fi

MW_ROOT="$SITE_ROOT/private/mw"
mkdir -p "$MW_ROOT"

rsync -a \
  --delete \
  --exclude=.git \
  --exclude=node_modules \
  --exclude=.env \
  --exclude=storage/logs \
  --exclude='storage/framework/sessions/*' \
  --exclude='storage/framework/views/*' \
  --exclude='storage/framework/cache/*' \
  "$SOURCE/" "$MW_ROOT/"

mkdir -p "$MW_ROOT/storage/framework/"{sessions,views,cache,data}
mkdir -p "$MW_ROOT/storage/logs"
mkdir -p "$MW_ROOT/bootstrap/cache"
chmod -R ug+rwX "$MW_ROOT/storage" "$MW_ROOT/bootstrap/cache" 2>/dev/null || true

APP_KEY="$(cd "$MW_ROOT" && php -r "echo 'base64:'.base64_encode(random_bytes(32));")"

if [[ "$USE_SQLITE" == "1" ]]; then
  mkdir -p "$MW_ROOT/database"
  SQLITE_PATH="$MW_ROOT/database/microweber.sqlite"
  touch "$SQLITE_PATH"
  {
    echo "APP_NAME=\"${APP_BRAND} Microweber\""
    echo "APP_ENV=production"
    echo "APP_KEY=${APP_KEY}"
    echo "APP_DEBUG=false"
    echo "APP_URL=${APP_URL}"
    echo ""
    echo "DB_CONNECTION=sqlite"
    echo "DB_DATABASE=${SQLITE_PATH}"
    echo ""
    echo "CACHE_DRIVER=file"
    echo "SESSION_DRIVER=file"
    echo "QUEUE_CONNECTION=sync"
    echo ""
    echo "CMS_BRIDGE_CONFIG=${CMS_BRIDGE}"
    echo "CMS_SSO_SECRET=${CMS_SSO}"
  } > "$MW_ROOT/.env"
else
  {
    echo "APP_NAME=\"${APP_BRAND} Microweber\""
    echo "APP_ENV=production"
    echo "APP_KEY=${APP_KEY}"
    echo "APP_DEBUG=false"
    echo "APP_URL=${APP_URL}"
    echo ""
    echo "DB_CONNECTION=mysql"
    echo "DB_HOST=127.0.0.1"
    echo "DB_PORT=3306"
    echo "DB_DATABASE=${DB_NAME}"
    echo "DB_USERNAME=${DB_USER}"
    echo "DB_PASSWORD=${DB_PASS}"
    echo ""
    echo "CACHE_DRIVER=file"
    echo "SESSION_DRIVER=file"
    echo "QUEUE_CONNECTION=sync"
    echo ""
    echo "CMS_BRIDGE_CONFIG=${CMS_BRIDGE}"
    echo "CMS_SSO_SECRET=${CMS_SSO}"
  } > "$MW_ROOT/.env"
fi

# When --mw-at-root is in play, the admin entry should generate public View URLs
# rooted at the host (no /mw prefix). app/Providers/AppServiceProvider.php picks
# this up via env('MW_PUBLIC_URL_ROOT'). Drayton-style installs (no --mw-at-root)
# never see this flag and keep emitting /mw/<slug> View URLs by design.
if [[ "$MW_AT_ROOT" == "1" ]] && ! grep -q '^MW_PUBLIC_URL_ROOT=' "$MW_ROOT/.env"; then
  {
    echo ""
    echo "# AppServiceProvider strips /mw from content/category link() output when set."
    echo "MW_PUBLIC_URL_ROOT=1"
  } >> "$MW_ROOT/.env"
fi

PUB_MW="$SITE_ROOT/public/mw"
mkdir -p "$PUB_MW"

cat > "$PUB_MW/index.php" <<'PHP'
<?php

declare(strict_types=1);

define('LARAVEL_START', microtime(true));

$mwSubdir = '/mw';

if (isset($_SERVER['REQUEST_URI'])) {
    $u = parse_url($_SERVER['REQUEST_URI']);
    $path = $u['path'] ?? '/';
    if ($path === $mwSubdir || str_starts_with($path, $mwSubdir . '/')) {
        $trim = substr($path, strlen($mwSubdir)) ?: '/';
        $query = isset($u['query']) ? '?' . $u['query'] : '';
        $_SERVER['REQUEST_URI'] = $trim . $query;
    }
}
$_SERVER['SCRIPT_NAME'] = $mwSubdir . '/index.php';

$siteRoot = dirname(__DIR__, 2);
$mwRoot = $siteRoot . '/private/mw';

if (!is_file($mwRoot . '/vendor/autoload.php')) {
    http_response_code(503);
    header('Content-Type: text/plain; charset=utf-8');
    echo "Microweber is not installed under private/mw (missing vendor).";
    exit;
}

require $mwRoot . '/vendor/autoload.php';
trait_exists('Illuminate\\Support\\Traits\\Conditionable', true);
$app = require_once $mwRoot . '/bootstrap/app.php';

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$request = Illuminate\Http\Request::capture();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
PHP

# Mirror Vite build output from the Laravel public/ tree (which lives under
# /private/mw) into the web-accessible /public/mw/ so that
# /mw/build/assets/*.js and *.css resolve as physical files. Without this
# the admin sidebar's Vue/Alpine bundle 404s and the placeholder skeleton
# classes never get removed.
if [[ -d "$MW_ROOT/public/build" ]]; then
  rsync -a --delete "$MW_ROOT/public/build/" "$PUB_MW/build/"
fi
if [[ -f "$MW_ROOT/public/favicon.ico" ]]; then
  cp -f "$MW_ROOT/public/favicon.ico" "$PUB_MW/favicon.ico"
fi

# Do NOT mirror public/admin/ or public/assets/ — those are remnants from
# alternative deployment topologies (and earlier custom-CMS integration glue)
# that contain a non-Laravel admin/index.php. If present in public/mw/,
# Apache serves it directly and bypasses Laravel routing, breaking /mw/admin.
for stray in admin assets "https:"; do
  if [[ -d "$PUB_MW/$stray" ]]; then
    rm -rf "$PUB_MW/$stray"
  fi
done

cat > "$PUB_MW/.htaccess" <<'HT'
<IfModule mod_negotiation.c>
  Options -MultiViews -Indexes
</IfModule>
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /mw/
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]
</IfModule>
<IfModule mod_headers.c>
  # Microweber's admin / Livewire rely on inline <script> blocks and eval.
  # Override any site-wide CSP only for this subdirectory.
  Header always unset Content-Security-Policy
  Header always set Content-Security-Policy "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https: wss:; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; object-src 'none'"
</IfModule>
HT

# Tag the subdir entry with MW_ENTRY='subdir' so AppServiceProvider knows to
# generate /mw/... URLs from this entry. Idempotent: only adds the line once.
if ! grep -q "define\\('MW_ENTRY'" "$PUB_MW/index.php" 2>/dev/null; then
  python3 - "$PUB_MW/index.php" <<'PY'
import sys, pathlib
p = pathlib.Path(sys.argv[1])
src = p.read_text()
needle = "define('LARAVEL_START', microtime(true));"
add = (
    "\n// Dual-entry signal: this script handles /mw/* requests (admin, MW utility\n"
    "// pages). AppServiceProvider reads MW_ENTRY to decide whether outgoing URLs\n"
    "// should be rooted at APP_URL (subdir) or at the bare host (root).\n"
    "define('MW_ENTRY', 'subdir');\n"
)
if needle in src and add.strip() not in src:
    p.write_text(src.replace(needle, needle + add))
PY
fi

# === MW frontend at root URLs (Approach C baseline) =========================
# Drop the root-entry shim, root .htaccess, and asset symlinks. After this the
# site can render MW pages at clean root URLs (domain.net/about-us) while the
# admin stays at /mw/admin and any existing PHP files (apply.php, book.php,
# /admin/ custom CMS, etc.) keep their paths intact.

PUB_ROOT="$SITE_ROOT/public"

cat > "$PUB_ROOT/_mw_router.php" <<'PHP'
<?php

declare(strict_types=1);

// Public-frontend front door for the Microweber Laravel app deployed at
// ../private/mw. All non-file/non-dir requests under the doc root land here
// (see public/.htaccess catch-all). REQUEST_URI is passed through untouched
// so MW's router resolves slugs at the document root (e.g. "/about-us").
//
// Dual-entry signal -- AppServiceProvider reads MW_ENTRY to decide whether
// outgoing URLs (links, asset paths) should be at the bare host ("root") or
// under the /mw subdirectory ("subdir", which is what public/mw/index.php
// uses for the admin UI).

define('LARAVEL_START', microtime(true));
define('MW_ENTRY', 'root');

$siteRoot = dirname(__DIR__);
$mwRoot   = $siteRoot . '/private/mw';

if (!is_file($mwRoot . '/vendor/autoload.php')) {
    http_response_code(503);
    header('Content-Type: text/plain; charset=utf-8');
    echo "Microweber is not installed under private/mw (missing vendor).";
    exit;
}

require $mwRoot . '/vendor/autoload.php';
trait_exists('Illuminate\\Support\\Traits\\Conditionable', true);
$app = require_once $mwRoot . '/bootstrap/app.php';

$kernel   = $app->make(Illuminate\Contracts\Http\Kernel::class);
$request  = Illuminate\Http\Request::capture();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
PHP

# Only write public/.htaccess if it doesn't already exist. Existing sites may
# have a hand-tuned one; we don't want to clobber custom rules. Operators who
# want the new rules can `rm public/.htaccess` and re-run, or merge by hand.
if [[ ! -f "$PUB_ROOT/.htaccess" ]]; then
  cat > "$PUB_ROOT/.htaccess" <<'HT'
# Microweber root-URL routing. Real files/dirs always win; everything else is
# handed to _mw_router.php (MW frontend in MW_ENTRY=root mode).

<IfModule mod_negotiation.c>
  Options -MultiViews
</IfModule>

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Existing custom CMS at /admin and MW admin at /mw stay on the filesystem;
  # never let the MW frontend router swallow them.
  RewriteRule ^admin($|/) - [L]
  RewriteRule ^mw($|/)    - [L]

  # Real files / dirs win.
  RewriteCond %{REQUEST_FILENAME} -f [OR]
  RewriteCond %{REQUEST_FILENAME} -d
  RewriteRule ^ - [L]

  # Catch-all for clean MW slugs at the doc root (e.g. /about-us).
  RewriteRule ^ _mw_router.php [L]
</IfModule>

<IfModule mod_headers.c>
  # MW-rendered HTML at root URLs needs the same relaxed CSP we already use
  # under /mw/ (inline <script>, runtime mw.* hooks, Vite-built assets).
  Header always unset Content-Security-Policy
  Header always set Content-Security-Policy "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; connect-src 'self' https: wss:; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; object-src 'none'"
</IfModule>
HT
else
  echo "Note: $PUB_ROOT/.htaccess already exists; leaving in place. If you want"
  echo "      MW frontend at root URLs, ensure it routes non-file/dir requests"
  echo "      to _mw_router.php and lets /admin and /mw pass through."
fi

# Asset symlinks at the doc root: MW emits /userfiles/... and /build/... URLs
# in MW_ENTRY=root mode; these need to resolve as physical files.
ensure_symlink() {
  local link="$1" target="$2"
  if [[ -L "$link" ]]; then
    [[ "$(readlink "$link")" == "$target" ]] || { rm -f "$link"; ln -s "$target" "$link"; }
  elif [[ -e "$link" ]]; then
    echo "Note: $link exists and is not a symlink; not replacing." >&2
  else
    ln -s "$target" "$link"
  fi
}
ensure_symlink "$PUB_ROOT/userfiles" "../private/mw/userfiles"
ensure_symlink "$PUB_ROOT/build"     "../private/mw/public/build"

echo "Deployed Microweber to:"
echo "  Laravel: $MW_ROOT"
echo "  Public:  $PUB_MW"
echo "  Root entry: $PUB_ROOT/_mw_router.php (+ root .htaccess + symlinks)"
if [[ "$MW_AT_ROOT" == "1" ]]; then
  echo "  Root mode: MW_PUBLIC_URL_ROOT=1 in .env (admin View URLs strip /mw)."
  echo "             To activate the See Thru IT theme post-install, pass"
  echo "               --site-template seethruit"
  echo "             to finalize_mw_mysql.sh (or any other theme name shipped"
  echo "             under userfiles/templates/)."
fi
if [[ "$USE_SQLITE" == "1" ]]; then
  echo "SQLite DB at $MW_ROOT/database/microweber.sqlite — run:"
  echo "  cd $MW_ROOT && php artisan microweber:install --db-driver=sqlite --db-name=database/microweber.sqlite --email=you@example.com --username=admin --password=ChooseStrong --default-content=0"
else
  echo "Next (once MySQL DB exists and credentials work):"
  echo "  cd $MW_ROOT && php artisan microweber:install --db-host=127.0.0.1 --db-name=$DB_NAME --db-username=$DB_USER --db-password=... --db-driver=mysql --email=you@example.com --username=admin --password=ChooseStrong --default-content=0"
fi

# Optional: import the existing live homepage as a MW 'Site Homepage' page so
# operators can edit it in /mw/admin/page on day one. Requires MW already to be
# microweber:install'd (so the content table exists). We therefore skip this
# in deploy and ask the operator to invoke it after finalize_mw_mysql.sh.
if [[ -n "$HOMEPAGE_URL" ]]; then
  IMPORT_FLAGS=""
  if [[ "$MW_AT_ROOT" == "1" ]]; then IMPORT_FLAGS+=" --mw-at-root"; fi
  echo
  echo "After finalize_mw_mysql.sh succeeds, import the existing homepage with:"
  echo "  bash $(dirname "$(readlink -f "$0")")/import_homepage_into_mw.sh \\"
  echo "    --site-root '$SITE_ROOT' --homepage-url '$HOMEPAGE_URL'$IMPORT_FLAGS"
fi

if [[ "$MW_AT_ROOT" == "1" ]]; then
  # Approach B: install the MW shim as public/index.php with a classic
  # fallback. The original public/index.php (if any) is preserved as
  # public/index-classic.php so the site can always degrade gracefully.
  SHIM_TEMPLATE="$(dirname "$(readlink -f "$0")")/system/index-mw-shim.php"
  if [[ ! -f "$SHIM_TEMPLATE" ]]; then
    echo "Warning: $SHIM_TEMPLATE missing; skipping Approach B install. The MW"
    echo "         router is in place; replace public/index.php manually if you"
    echo "         want MW to serve /."
  else
    if [[ -f "$PUB_ROOT/index.php" && ! -f "$PUB_ROOT/index-classic.php" ]]; then
      mv "$PUB_ROOT/index.php" "$PUB_ROOT/index-classic.php"
      echo "Approach B: backed up $PUB_ROOT/index.php -> index-classic.php"
    elif [[ -f "$PUB_ROOT/index-classic.php" ]]; then
      echo "Approach B: $PUB_ROOT/index-classic.php already exists; leaving it"
      echo "            in place (treating as the canonical classic fallback)."
    fi
    install -m 0644 "$SHIM_TEMPLATE" "$PUB_ROOT/index.php"
    echo "Approach B: installed MW shim at $PUB_ROOT/index.php"
    echo "            (falls back to index-classic.php if MW kernel fails)"
  fi
fi

if [[ "$PUBLISH_TO_PARTIAL" == "1" ]]; then
  echo
  echo "Approach A (MW publishes to a partial): set"
  echo "  STI_HOMEPAGE_PUBLISH_TO_PARTIAL=1"
  echo "  STI_HOMEPAGE_PARTIAL_PATH=public/includes/mw-homepage.html"
  echo "in $MW_ROOT/.env, then ensure your existing public/index.php includes"
  echo "the partial inside <main>:"
  echo "  <?php @include __DIR__ . '/includes/mw-homepage.html'; ?>"
fi
