# Easy WP Bootstrap — Windows (PowerShell + Herd) — local wp-cli.phar via php.exe

Param(
  [Parameter(Mandatory=$true)][string]$ProjectName,
  [string]$AdminUser,
  [string]$AdminEmail,
  [string]$ThemeStarterRepo,
  [string]$HerdWorkspace,
  [string]$LocalTld,
  [string]$MysqlHost,
  [string]$MysqlPort,
  [string]$MysqlRootUser,
  [string]$MysqlRootPass
)

$ErrorActionPreference = 'Stop'
$env:WP_CLI_STRICT_ARGS_MODE = '1'

# ---- Load rc (CLI > rc > hard default) ----
$RcFile = Join-Path $HOME ".wp-bootstraprc"
$Rc = @{}
if (Test-Path $RcFile) {
  Get-Content $RcFile | ForEach-Object {
    $line = $_.Trim()
    if ($line -match '^\s*#' -or $line -match '^\s*$') { return }
    if ($line -match '^\s*([^=]+)=(.+)$') {
      $key = $matches[1].Trim()
      $val = $matches[2].Trim('"'' ')
      $val = $val -replace '\$HOME', [Regex]::Escape($HOME)
      $val = $val -replace '^~', [Regex]::Escape($HOME)
      $val = $val -replace '\\\\','\'
      $Rc[$key] = $val
    }
  }
}
function RcOr([string]$Key,[string]$Fallback){ if($Rc.ContainsKey($Key) -and $Rc[$Key]){$Rc[$Key]}else{$Fallback} }

if (-not $AdminUser)        { $AdminUser        = RcOr "DEFAULT_ADMIN_USER"  "vdidev" }
if (-not $AdminEmail)       { $AdminEmail       = RcOr "DEFAULT_ADMIN_EMAIL" "dev@vincentdesign.ca" }
if (-not $ThemeStarterRepo) { $ThemeStarterRepo = RcOr "THEME_STARTER_REPO"  "https://github.com/WordPress/twentytwentyfour" }
if (-not $HerdWorkspace)    { $HerdWorkspace    = RcOr "HERD_WORKSPACE"      "$HOME\Herd" }
if (-not $LocalTld)         { $LocalTld         = RcOr "LOCAL_TLD"           "test" }
if (-not $MysqlHost)        { $MysqlHost        = RcOr "MYSQL_HOST"          "127.0.0.1" }
if (-not $MysqlPort)        { $MysqlPort        = RcOr "MYSQL_PORT"          "3306" }
if (-not $MysqlRootUser)    { $MysqlRootUser    = RcOr "MYSQL_ROOT_USER"     "root" }
if (-not $MysqlRootPass)    { $MysqlRootPass    = RcOr "MYSQL_ROOT_PASS"     "" }

# ---- Helpers ----
function Slugify([string]$s){ ($s.ToLower() -replace '[^a-z0-9]+','-').Trim('-') }

function RandPass(){
  $b = New-Object 'System.Byte[]' 48
  (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($b)
  $raw = [Convert]::ToBase64String($b) -replace '[^a-zA-Z0-9]',''
  while($raw.Length -lt 24){
    $b2 = New-Object 'System.Byte[]' 16
    (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($b2)
    $raw += ([Convert]::ToBase64String($b2) -replace '[^a-zA-Z0-9]','')
  }
  $raw.Substring(0,24)
}

# Resolve script folder + absolute phar
$ScriptRoot = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Definition }

$PharFullPath = Join-Path $ScriptRoot 'wp-cli.phar'

if (!(Test-Path $PharFullPath)) { throw "wp-cli.phar not found at: $PharFullPath" }

# Resolve Herd php.exe (parse php.bat or derive from php -v → $HOME\.config\herd\bin\<ver>\php.exe)
function Resolve-PhpExe {
  $phpCmd = Get-Command php -ErrorAction SilentlyContinue
  if ($phpCmd -and ($phpCmd.Source -match '\.bat$') -and (Test-Path $phpCmd.Source)) {
    $bat = Get-Content -Raw $phpCmd.Source
    $m = [regex]::Match($bat, '(["'']?)(%[^"''\r\n]+%|[A-Za-z]:\\[^"''\r\n]+?\\php\.exe)\1')
    if ($m.Success) {
      $raw = $m.Groups[2].Value
      $exp = [Environment]::ExpandEnvironmentVariables($raw)
      if (Test-Path $exp) { return $exp }
    }
  }

  try {
    $verOut = & cmd.exe /d /s /c 'php -v' 2>&1
    $verLine = ($verOut | Select-Object -First 1)
    $m2 = [regex]::Match($verLine, 'PHP\s+(\d+\.\d+\.\d+)')
    if ($m2.Success) {
      $ver = $m2.Groups[1].Value
      $cand = Join-Path $HOME ".config\herd\bin\$ver\php.exe"
      if (Test-Path $cand) { return $cand }
    }
  } catch {}
  $whereExe = (& where.exe php 2>$null) -split "`r?`n" | Where-Object { $_ -match '\.exe$' } | Select-Object -First 1
  if ($whereExe -and (Test-Path $whereExe)) { return $whereExe }
  throw "Could not resolve a real php.exe (expected like $HOME\.config\herd\bin\<ver>\php.exe)."
}

$PhpExe = Resolve-PhpExe

# ---- WP-CLI wrapper: space-safe (runs php from script folder) ----
function Invoke-WP {
  [CmdletBinding(PositionalBinding=$false)]
  param(
    [Parameter(ValueFromRemainingArguments=$true)]
    [string[]]$WpArgs
  )

  # WordPress installation directory (do not change)
  $wpPath = ((Get-Location).Path) -replace '\\','/'

  # Always run PHP from the folder that contains wp-cli.phar to avoid spaces in the script path
  $orig = Get-Location
  try {
    Push-Location $ScriptRoot

    # Use -f and -- to separate PHP options from WP-CLI args
    # Format executed:  php -f wp-cli.phar -- --path=<project-dir> <wp-cli-args…>
    $all = @("-f", "wp-cli.phar", "--", "--path=$wpPath") + $WpArgs

    # DEBUG (optional): uncomment to see exactly what's executed
    # Write-Host ">> $PhpExe $($all -join ' ') (cwd=$((Get-Location).Path))"

    $out = & $PhpExe @all 2>&1

    # DEBUG (optional): uncomment to see full output
    # $out | Out-Host

    if ($LASTEXITCODE -ne 0) {
      throw "WP-CLI failed (exit $LASTEXITCODE): $PhpExe $($all -join ' ') (cwd=$((Get-Location).Path))"
    }
    return $out
  }
  finally {
    Pop-Location | Out-Null
  }
}

# ---- Compute basics ----
$Slug        = Slugify $ProjectName
$ProjectDir  = Join-Path $HerdWorkspace $Slug
$LocalUrl    = "http://$Slug.$LocalTld"
$DbName      = "wp_$Slug"
$DbUser      = $DbName
$DbPass      = RandPass
$AdminPass   = RandPass

Write-Host "Creating project at $ProjectDir...`n"
New-Item -ItemType Directory -Force -Path $ProjectDir | Out-Null
Set-Location $ProjectDir

# Sanity print
$pathShown = ((Get-Location).Path -replace '\\','/')
Write-Host "WP-CLI php:  $PhpExe"
Write-Host "WP-CLI phar: $PharFullPath"
Write-Host "WP-CLI --path: --path=$pathShown"
Invoke-WP "cli" "version"

# ---- WP Core ----
Write-Host "`nDownloading WordPress core..."
Invoke-WP "core" "download" "--force"

# ---------- Database (DBngin/MySQL) ----------
Write-Host "`nCreating MySQL DB and user..."

# Build root arg list
$mysqlArgsRoot = @("-h", $MysqlHost, "-P", $MysqlPort, "-u", $MysqlRootUser)
if ($MysqlRootPass -ne "") { $mysqlArgsRoot += "-p$MysqlRootPass" }

# Sanity: confirm root can connect
$null = & mysql.exe @mysqlArgsRoot -e "SELECT VERSION();" 2>$null
if ($LASTEXITCODE -ne 0) {
  throw ("Cannot connect to MySQL as root ({0}@{1}:{2}). Check MYSQL_ROOT_* in your rc file." -f $MysqlRootUser, $MysqlHost, $MysqlPort)
}

# Build SQL without any escaping sequences in PowerShell strings.
# Use a real backtick char for MySQL identifiers:
$bt = [char]96  # `
$dbIdent = "$bt$DbName$bt"

$sqlParts = @(
  "CREATE DATABASE IF NOT EXISTS $dbIdent CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;",
  "",
  "CREATE USER IF NOT EXISTS '$DbUser'@'localhost'   IDENTIFIED BY '$DbPass';",
  "CREATE USER IF NOT EXISTS '$DbUser'@'127.0.0.1'   IDENTIFIED BY '$DbPass';",
  "CREATE USER IF NOT EXISTS '$DbUser'@'%'           IDENTIFIED BY '$DbPass';",
  "",
  "GRANT ALL PRIVILEGES ON $dbIdent.* TO '$DbUser'@'localhost';",
  "GRANT ALL PRIVILEGES ON $dbIdent.* TO '$DbUser'@'127.0.0.1';",
  "GRANT ALL PRIVILEGES ON $dbIdent.* TO '$DbUser'@'%';",
  "FLUSH PRIVILEGES;"
)

$tmpSql = [System.IO.Path]::GetTempFileName()
[System.IO.File]::WriteAllLines($tmpSql, $sqlParts, [System.Text.Encoding]::UTF8)

# Feed the SQL file to mysql via cmd redirection (reliable on Windows)
function Quote-ForCmd([string]$s){ '"' + ($s -replace '"','""') + '"' }

$cmdLine = "mysql.exe " + (
  ($mysqlArgsRoot | ForEach-Object { Quote-ForCmd $_ }) -join ' '
) + " < " + (Quote-ForCmd $tmpSql)

# DEBUG (optional): uncomment to see exactly what's run
# Write-Host ">> $cmdLine"

& cmd.exe /d /s /c $cmdLine
$exit = $LASTEXITCODE

# Clean up the temp file regardless
Remove-Item -Force $tmpSql -ErrorAction SilentlyContinue

if ($exit -ne 0) {
  throw "MySQL SQL error while creating DB/user. Verify root creds and server."
}

# Verify the NEW user can actually select the DB (fail fast if not)
$mysqlArgsUser = @("-h", $MysqlHost, "-P", $MysqlPort, "-u", $DbUser, "-p$DbPass", "-D", $DbName)
$null = & mysql.exe @mysqlArgsUser -e "SELECT 1;" 2>$null
if ($LASTEXITCODE -ne 0) {
  throw ("New MySQL user cannot access DB '{0}' via {1}:{2}. Host match or privileges issue — check users and grants." -f $DbName, $MysqlHost, $MysqlPort)
}

# ---- Config + Install ----
Invoke-WP "config" "create" "--dbname=$DbName" "--dbuser=$DbUser" "--dbpass=$DbPass" "--dbhost=$($MysqlHost):$($MysqlPort)" "--force"
Invoke-WP "config" "shuffle-salts"
Invoke-WP "core" "install" "--url=$LocalUrl" "--title=$ProjectName" "--admin_user=$AdminUser" "--admin_password=$AdminPass" "--admin_email=$AdminEmail"
Invoke-WP "option" "update" "siteurl" $LocalUrl
Invoke-WP "option" "update" "home" $LocalUrl

# ---- Pages & Reading ----
Write-Host "Creating Home/News pages and setting permalinks..."
$homeId = (Invoke-WP "post" "create" "--post_type=page" "--post_status=publish" "--post_title=Home" "--porcelain" | Select-Object -Last 1).Trim()
$newsId = (Invoke-WP "post" "create" "--post_type=page" "--post_status=publish" "--post_title=News" "--porcelain" | Select-Object -Last 1).Trim()
Invoke-WP "option" "update" "show_on_front" "page"
Invoke-WP "option" "update" "page_on_front" $homeId
Invoke-WP "option" "update" "page_for_posts" $newsId
Invoke-WP "rewrite" "structure" "/%postname%/"
Invoke-WP "rewrite" "flush" "--hard"

# --- Ensure .htaccess exists (for Apache/permalinks) ---
$htFile = Join-Path $ProjectDir ".htaccess"
if (!(Test-Path $htFile)) {
  $ht = @"
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
"@
  Set-Content -Path $htFile -Value $ht -Encoding ASCII
  Write-Host "`nCreated default .htaccess"
}

# ---- Theme ----
Write-Host "`nCloning starter theme..."
$tmp = ".starter-tmp"
if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp }
git clone --depth=1 $ThemeStarterRepo $tmp | Out-Null

$ThemeDir = "wp-content\themes\$Slug"
if (Test-Path $ThemeDir) { Remove-Item -Recurse -Force $ThemeDir }
New-Item -ItemType Directory -Force -Path (Split-Path $ThemeDir) | Out-Null
Move-Item $tmp $ThemeDir
if (Test-Path "$ThemeDir\.git") { Remove-Item -Recurse -Force "$ThemeDir\.git" }

# --- Stamp Theme Name + Text Domain into style.css ---
$styleCss    = Join-Path $ThemeDir "style.css"
$TextDomain  = "$Slug"   # matches your theme folder name
if (Test-Path $styleCss) {
  $css = Get-Content $styleCss -Raw

  # Replace existing "Theme Name:" line (supports plain or "* Theme Name:" formats)
  $css = [regex]::Replace(
    $css,
    '(?im)^(?:\s*\*\s*)?Theme\s+Name\s*:\s*.*$',
    " * Theme Name: $ProjectName"
  )

  Set-Content -Path $styleCss -Value $css -Encoding UTF8
  Write-Host "`nUpdated style.css header with Theme Name: $ProjectName`n"
}

Invoke-WP "theme" "activate" "$Slug"

Push-Location $ThemeDir
# ---- Init theme dependencies and build Tailwind ----
Write-Host "`nInstalling theme dependencies and building assets..."
composer install 2>$null
npm install 2>$null
npm run build 2>$null

# ---- Init new git repo ----
Write-Host "`nInitializing new git repo for theme..."
git init -b main | Out-Null
git add -A
git commit -m "feat: bootstrap ${ProjectName} theme from starter" | Out-Null
Pop-Location

# ---------- Plugins (optional) ----------
# Look for plugins.json in the project, then fall back to script folder
$PluginsFileProject = Join-Path $ProjectDir "plugins.json"
$PluginsFileScript  = Join-Path $ScriptRoot "plugins.json"
$PluginsFile  = if (Test-Path $PluginsFileProject) { $PluginsFileProject }
                elseif (Test-Path $PluginsFileScript) { $PluginsFileScript }
                else { $null }

if ($PluginsFile) {
  try {
    Write-Host "`nInstalling plugins from $PluginsFile..."
    $plugins = Get-Content $PluginsFile -Raw | ConvertFrom-Json
    foreach ($plugin in $plugins) {
      if ($plugin.zip) {
        $args = @("plugin","install",$plugin.zip,"--force")
        if ($plugin.activate -eq $true) { $args += "--activate" }
        Invoke-WP @args
      } elseif ($plugin.slug) {
        $args = @("plugin","install",$plugin.slug,"--force")
        if ($plugin.version) { $args += "--version=$($plugin.version)" }
        if ($plugin.activate -eq $true) { $args += "--activate" }
        Invoke-WP @args
      }
    }
  } catch {
    Write-Host "`nPlugin install error: $_"
  }
} else {
  Write-Host "`nNo plugins.json found in project or script folder; skipping plugins."
}

# ---- Summary ----
$Summary = @"
Easy WP Bootstrap — Summary
===========================

Project:         $ProjectName
Slug:            $Slug
Folder:          $ProjectDir
Theme Dir:       $ThemeDir

DB Host:         $MysqlHost
DB Port:         $MysqlPort
DB Name:         $DbName
DB User:         $DbUser
DB Pass:         $DbPass

Local URL:       $LocalUrl
Local Admin URL: $LocalUrl/wp-admin/

WP Admin Email:  $AdminEmail
WP Admin User:   $AdminUser
WP Admin Pass:   $AdminPass
"@

$SummaryFile = Join-Path $ProjectDir "bootstrap-summary.txt"

$Summary | Out-File -FilePath $SummaryFile -Encoding utf8

Write-Host "`n`n$Summary"
Write-Host "`nSaved summary to $SummaryFile"
