#!/bin/bash
set -u

#==============================================================================
# Copyright and license info is available in the LICENSE file included with
# the Server Deployment Package (SDP), and also available online:
# https://workshop.perforce.com/projects/p4sudo/view/main/LICENSE
#------------------------------------------------------------------------------
# mkblackbelt.sh — P4Sudo command script: Bootstrap Black Belt customer on PPN
#
# Site-defined command script called by p4sudo.sh when an authorized user runs:
#     p4 sudo mkblackbelt <CustomerTag> [options]
#
# Performs a 9-step workflow: validates inputs, provisions the customer's P4
# depot and stream on PPN, submits an INFO.md instantiated from a template, and
# adds a row to the Black Belt Customer Index.
#
# IMPORTANT: stdout is the broker protocol channel (inherited from p4sudo.sh).
# Write only the final result message to stdout. All intermediate progress is
# written to a per-invocation log file. (See broker-rewrite-reference/README.md.)
#
# On any step failure, the ephemeral workspace (if created) is left in place for
# debugging. Detailed failure context is in the log.
#
# Called by:  p4sudo.sh (type=script dispatch)
# Deployment: /p4/common/site/p4sudo/commands/mkblackbelt.sh
# Config:     ${P4SUDO_CFG:-/p4/common/site/config/p4sudo.cfg}

#==============================================================================
# Declarations and Environment

declare ThisScript=${0##*/}
declare Version=1.0.0
declare -i ErrorCount=0
declare -i WarningCount=0
declare Log=

declare SDPInstance=${SDP_INSTANCE:-1}
declare SDPRoot=${SDP_ROOT:-/p4}
declare SDPCommon="$SDPRoot/common"
declare SDPCommonLib="$SDPCommon/lib"
declare LOGS="${LOGS:-$SDPRoot/$SDPInstance/logs}"

# Broker context — injected into the environment by p4sudo.sh.
declare P4Port="${P4SUDO_P4PORT:-}"
declare P4SudoUser="${P4SUDO_USER:-}"
declare RequestingUser="${P4SUDO_REQUESTING_USER:-}"

# Parsed inputs — required.
declare CustomerTag=
declare SalesforceLink=
declare Tier=
declare CommsChannel=
declare ProgramStartDate=
declare ProgramEndDate=
declare LicensedUsers=
declare BackgroundUsers=
declare Contact1Name='' Contact1Email='' Contact1Role=''
declare P4PrimaryName='' P4PrimaryEmail='' P4PrimaryRole=''

# Parsed inputs — optional.
declare IndexNotes=
declare Contact2Name='' Contact2Email='' Contact2Role=''
declare P4SecondaryName='' P4SecondaryEmail='' P4SecondaryRole=''
declare P4Extra1Name='' P4Extra1Email='' P4Extra1Role=''
declare P4Extra2Name='' P4Extra2Email='' P4Extra2Role=''

# Auto-populated at runtime.
declare ActivationDate=     # YYYY/MM/DD — today

# Ephemeral workspace — populated after successful creation; left for debugging
# on any error, deleted only on full success (step 8).
declare EphemeralWs=
declare EphemeralRoot=

# P4 paths and known workspace names.
declare BlackBeltWs="p4sudo-svc.blackbelt"
declare TemplateDepotPath="//BlackBelt/main/docs/INFO.md.template"
declare CustomerIndexDepotPath="//BlackBelt/main/Customers/CustomerIndex.md"

declare H1="=============================================================================="

#==============================================================================
# Local Functions

function msg     () { echo -e "$*"; }
function errmsg  () { msg "Error: ${1:-Unknown Error}"; ErrorCount+=1; }
function warnmsg () { msg "Warning: ${1:-Unknown Warning}"; WarningCount+=1; }
function bail    () { errmsg "${1:-Unknown Error}"; exit "${2:-1}"; }

#------------------------------------------------------------------------------
# Function: log_write
function log_write ()
{
   local level="${1:-INFO}"; shift
   [[ -n "$Log" && "$Log" != off ]] && \
      echo "$(date '+%Y-%m-%dT%H:%M:%S') [$level] $*" >> "$Log"
}

#------------------------------------------------------------------------------
# Function: p4cmd
# Run a p4 command as the service account against the configured P4 port.
function p4cmd ()
{
   p4 -p "$P4Port" -u "$P4SudoUser" "$@"
}

#------------------------------------------------------------------------------
# Function: do_subst
# Replace a token with a value in a file (in-place, sed -i).
# Escapes sed replacement metacharacters (backslash, pipe, ampersand) in value.
function do_subst ()
{
   local token="$1" value="$2" file="$3"
   local esc
   esc=$(printf '%s' "$value" | sed 's/[\\|&]/\\&/g')
   sed -i "s|${token}|${esc}|g" "$file"
}

#------------------------------------------------------------------------------
# Function: insert_customer_row
# Insert newRow after the last table row in the Active Customers section of file.
# Uses awk to locate the section and find the last line starting with '|'.
function insert_customer_row ()
{
   local file="$1" row="$2"
   awk -v newRow="$row" '
   {
      if (/^## Active Customers/) { inSection=1 }
      else if (/^## /)            { inSection=0 }
      if (inSection && /^\|/)     { lastTableLine=NR }
      lines[NR]=$0
   }
   END {
      for (i=1; i<=NR; i++) {
         print lines[i]
         if (i==lastTableLine) print newRow
      }
   }' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
}

#------------------------------------------------------------------------------
# Function: validate_inputs
# Checks all required inputs and format constraints.
# Increments ErrorCount for each failure; caller bails if non-zero.
function validate_inputs ()
{
   # Required fields.
   [[ -z "$CustomerTag"      ]] && errmsg "CustomerTag is required (first positional argument)."
   [[ -z "$SalesforceLink"   ]] && errmsg "--salesforce-link is required."
   [[ -z "$Tier"             ]] && errmsg "--tier is required."
   [[ -z "$CommsChannel"     ]] && errmsg "--comms is required."
   [[ -z "$ProgramStartDate" ]] && errmsg "--start-date is required."
   [[ -z "$ProgramEndDate"   ]] && errmsg "--end-date is required."
   [[ -z "$LicensedUsers"    ]] && errmsg "--licensed-users is required."
   [[ -z "$BackgroundUsers"  ]] && errmsg "--background-users is required."
   [[ -z "$Contact1Name"     ]] && errmsg "--contact1-name is required."
   [[ -z "$Contact1Email"    ]] && errmsg "--contact1-email is required."
   [[ -z "$Contact1Role"     ]] && errmsg "--contact1-role is required."
   [[ -z "$P4PrimaryName"    ]] && errmsg "--p4primary-name is required."
   [[ -z "$P4PrimaryEmail"   ]] && errmsg "--p4primary-email is required."
   [[ -z "$P4PrimaryRole"    ]] && errmsg "--p4primary-role is required."

   [[ "$ErrorCount" -gt 0 ]] && return 1

   # CustomerTag: alphanumeric, any case, must not start with a digit.
   if [[ ! "$CustomerTag" =~ ^[A-Za-z][A-Za-z0-9]*$ ]]; then
      errmsg "CustomerTag must be alphanumeric (no spaces or special characters) and must not start with a digit: '$CustomerTag'"
   fi

   # Tier must be one of the three valid values.
   case "$Tier" in
      Standard|Enterprise|Essential) ;;
      *) errmsg "Tier must be Standard, Enterprise, or Essential: '$Tier'";;
   esac

   # Dates: YYYY/MM/DD.
   local datePattern='^[0-9]{4}/[0-9]{2}/[0-9]{2}$'
   [[ "$ProgramStartDate" =~ $datePattern ]] || errmsg "--start-date must be YYYY/MM/DD: '$ProgramStartDate'"
   [[ "$ProgramEndDate"   =~ $datePattern ]] || errmsg "--end-date must be YYYY/MM/DD: '$ProgramEndDate'"

   # Integers.
   [[ "$LicensedUsers"   =~ ^[0-9]+$ ]] || errmsg "--licensed-users must be a non-negative integer: '$LicensedUsers'"
   [[ "$BackgroundUsers" =~ ^[0-9]+$ ]] || errmsg "--background-users must be a non-negative integer: '$BackgroundUsers'"

   [[ "$ErrorCount" -gt 0 ]] && return 1
   return 0
}

#==============================================================================
# Load SDP Library Functions.

if [[ -d "$SDPCommonLib" ]]; then
   # shellcheck disable=SC1090 disable=SC1091
   source "$SDPCommonLib/logging.lib" ||\
      bail "Failed to load bash lib [$SDPCommonLib/logging.lib]. Aborting."
   # shellcheck disable=SC1090 disable=SC1091
   source "$SDPCommonLib/run.lib" ||\
      bail "Failed to load bash lib [$SDPCommonLib/run.lib]. Aborting."
fi

# run.lib declares its own Version; restore this script's version.
declare Version=1.0.0

# Override terminate() from logging.lib: stdout is the broker protocol channel.
# The library's terminate() prints "Log is: ..." to stdout, which would corrupt
# the broker protocol response. Write that information to the log instead.
# shellcheck disable=SC2317
function terminate ()
{
   trap - EXIT SIGINT SIGTERM
   log_write "INFO" "Exiting. ErrorCount=$ErrorCount Log=$Log"
   exit "$ErrorCount"
}

#------------------------------------------------------------------------------
# Function: usage (required function)
function usage ()
{
   local style=${1:--h}
   local usageErrorMessage=${2:-Unset}

   if [[ "$usageErrorMessage" != Unset ]]; then
      msg "\n\nUsage Error:\n\n$usageErrorMessage\n\n"
   fi

   msg "USAGE for $ThisScript v$Version:

$ThisScript <CustomerTag> \\
   --salesforce-link=<URL> \\
   --tier=<Standard|Enterprise|Essential> \\
   --comms=<channel> \\
   --start-date=<YYYY/MM/DD> --end-date=<YYYY/MM/DD> \\
   --licensed-users=<N> --background-users=<N> \\
   --contact1-name=<name> --contact1-email=<email> --contact1-role=<role> \\
   --p4primary-name=<name> --p4primary-email=<email> --p4primary-role=<role> \\
   [--notes=<text>] \\
   [--contact2-name=<name> --contact2-email=<email> --contact2-role=<role>] \\
   [--p4secondary-name=<name> --p4secondary-email=<email> --p4secondary-role=<role>] \\
   [--p4extra1-name=<name> --p4extra1-email=<email> --p4extra1-role=<role>] \\
   [--p4extra2-name=<name> --p4extra2-email=<email> --p4extra2-role=<role>]

or

$ThisScript [-h|-man|-V]
"
   if [[ "$style" == -man ]]; then
      msg "
DESCRIPTION:
   $ThisScript bootstraps a new Black Belt consulting customer on PPN.

   Steps performed:
     1. Validate inputs
     2. Fetch INFO.md template (//$TemplateDepotPath)
     3. Provision //<CustomerTag> stream depot (idempotent)
     4. Provision //<CustomerTag>/main stream (idempotent)
     5. Create ephemeral workspace for //<CustomerTag>/main
     6. Instantiate INFO.md from template (token substitution)
     7. Submit INFO.md to //<CustomerTag>/main/BlackBelt/INFO.md
     8. Delete ephemeral workspace (only on success)
     9. Update CustomerIndex.md via the '$BlackBeltWs' workspace

   On any step failure, the ephemeral workspace is left in place for debugging.
   A detailed per-invocation log is written to \$LOGS.
   All P4 operations run as the service account (P4SUDO_USER).

REQUIRED ARGUMENTS:
 <CustomerTag>
   Short identifier for the customer P4 depot. Alphanumeric, any case, no
   spaces, must not start with a digit. Becomes the depot name on PPN.

 --salesforce-link=<URL>   Salesforce opportunity or account URL.
 --tier=<tier>             Program tier: Standard, Enterprise, or Essential.
 --comms=<channel>         Comms channel (e.g. Slack #ext-acme-perforce-bb).
 --start-date=<YYYY/MM/DD> Program start date.
 --end-date=<YYYY/MM/DD>   Program end date.
 --licensed-users=<N>      Licensed user count (non-negative integer).
 --background-users=<N>    Background user count (non-negative integer).
 --contact1-name=<name>    Customer primary contact name.
 --contact1-email=<email>  Customer primary contact email.
 --contact1-role=<role>    Customer primary contact role/notes.
 --p4primary-name=<name>   P4 primary staff contact name.
 --p4primary-email=<email> P4 primary staff contact email.
 --p4primary-role=<role>   P4 primary staff contact role/notes.

OPTIONAL ARGUMENTS:
 --notes=<text>               Free-text notes for the Customer Index entry.
 --contact2-name/email/role   Second customer contact.
 --p4secondary-name/email/role  Second P4 staff contact.
 --p4extra1-name/email/role   Additional P4 staff contact (1).
 --p4extra2-name/email/role   Additional P4 staff contact (2).

HELP OPTIONS:
 -h    Display short help message.
 -man  Display man-style help message.
 -V    Display version info for this script.

ENVIRONMENT:
 P4SUDO_P4PORT            P4 port (set by p4sudo.sh dispatcher).
 P4SUDO_USER              Service account username (set by p4sudo.sh).
 P4SUDO_REQUESTING_USER   User who invoked 'p4 sudo mkblackbelt' (informational).

SEE ALSO:
 p4sudo.sh(1), doc/use-cases.md, doc/mkblackbelt.ui.yaml
"
   fi

   exit 2
}

#==============================================================================
# Command Line Processing

set +u
[[ $# -gt 0 && "$1" == -h      ]] && usage -h
[[ $# -gt 0 && "$1" == -man    ]] && usage -man
[[ $# -gt 0 && "$1" == --help  ]] && usage -man
[[ $# -gt 0 && ("$1" == -V || "$1" == --version) ]] && { msg "$ThisScript version $Version"; exit 0; }

# First positional argument is CustomerTag (not a flag).
[[ $# -gt 0 && "${1:0:1}" != "-" ]] && { CustomerTag="$1"; shift; }

while [[ $# -gt 0 ]]; do
   case "$1" in
      (--salesforce-link=*)    SalesforceLink="${1#*=}";;
      (--tier=*)               Tier="${1#*=}";;
      (--comms=*)              CommsChannel="${1#*=}";;
      (--notes=*)              IndexNotes="${1#*=}";;
      (--start-date=*)         ProgramStartDate="${1#*=}";;
      (--end-date=*)           ProgramEndDate="${1#*=}";;
      (--licensed-users=*)     LicensedUsers="${1#*=}";;
      (--background-users=*)   BackgroundUsers="${1#*=}";;
      (--contact1-name=*)      Contact1Name="${1#*=}";;
      (--contact1-email=*)     Contact1Email="${1#*=}";;
      (--contact1-role=*)      Contact1Role="${1#*=}";;
      (--contact2-name=*)      Contact2Name="${1#*=}";;
      (--contact2-email=*)     Contact2Email="${1#*=}";;
      (--contact2-role=*)      Contact2Role="${1#*=}";;
      (--p4primary-name=*)     P4PrimaryName="${1#*=}";;
      (--p4primary-email=*)    P4PrimaryEmail="${1#*=}";;
      (--p4primary-role=*)     P4PrimaryRole="${1#*=}";;
      (--p4secondary-name=*)   P4SecondaryName="${1#*=}";;
      (--p4secondary-email=*)  P4SecondaryEmail="${1#*=}";;
      (--p4secondary-role=*)   P4SecondaryRole="${1#*=}";;
      (--p4extra1-name=*)      P4Extra1Name="${1#*=}";;
      (--p4extra1-email=*)     P4Extra1Email="${1#*=}";;
      (--p4extra1-role=*)      P4Extra1Role="${1#*=}";;
      (--p4extra2-name=*)      P4Extra2Name="${1#*=}";;
      (--p4extra2-email=*)     P4Extra2Email="${1#*=}";;
      (--p4extra2-role=*)      P4Extra2Role="${1#*=}";;
      (*) usage -h "Unknown argument: $1";;
   esac
   shift
done
set -u

#==============================================================================
# Command Line Verification

[[ -z "$CustomerTag" ]] && usage -h "CustomerTag is required as the first positional argument."

# These env vars are set by p4sudo.sh; guard against direct invocation without them.
[[ -z "$P4Port"     ]] && bail "P4SUDO_P4PORT is not set. This script must be called by p4sudo.sh."
[[ -z "$P4SudoUser" ]] && bail "P4SUDO_USER is not set. This script must be called by p4sudo.sh."

#==============================================================================
# Main Program

trap terminate EXIT SIGINT SIGTERM

# Per-invocation log setup.
if [[ -d "${LOGS:-}" ]]; then
   Log="$LOGS/${ThisScript%.sh}.${CustomerTag}.$(date +'%Y-%m-%d-%H%M%S').log"
fi

log_write "INFO" "$H1"
log_write "INFO" "Starting $ThisScript v$Version"
log_write "INFO" "CustomerTag=$CustomerTag RequestingUser=${RequestingUser:-<unknown>} P4Port=$P4Port"

# Auto-populate dates and ephemeral workspace name.
ActivationDate=$(date '+%Y/%m/%d')
declare Timestamp
Timestamp=$(date '+%Y%m%d-%H%M%S')
EphemeralWs="p4sudo-mkblackbelt-${CustomerTag}-${Timestamp}"
EphemeralRoot="/tmp/${EphemeralWs}"

log_write "INFO" "ActivationDate=$ActivationDate EphemeralWs=$EphemeralWs"

#------------------------------------------------------------------------------
# Step 1 — Validate inputs.

log_write "INFO" "Step 1: Validating inputs."

validate_inputs || bail "Input validation failed. Correct the errors above and retry."

log_write "INFO" "Step 1: Inputs validated OK."

#------------------------------------------------------------------------------
# Step 2 — Fetch INFO.md template from PPN.

declare templateFile
templateFile=$(mktemp "/tmp/p4sudo-mkblackbelt-template.XXXXXX") || \
   bail "Step 2: Could not create temp file for template."

log_write "INFO" "Step 2: Fetching template $TemplateDepotPath -> $templateFile"

declare p4out
p4out=$(p4cmd print -q -o "$templateFile" "$TemplateDepotPath" 2>&1)
declare -i p4rc=$?

if (( p4rc != 0 )); then
   rm -f "$templateFile"
   bail "Step 2: Failed to fetch template from $TemplateDepotPath: $p4out"
fi

log_write "INFO" "Step 2: Template fetched OK."

#------------------------------------------------------------------------------
# Step 3 — Provision //<CustomerTag> stream depot (idempotent).

log_write "INFO" "Step 3: Checking depot //$CustomerTag."

declare existingDepot
existingDepot=$(p4cmd depots -e "$CustomerTag" 2>&1)

if [[ -n "$existingDepot" ]]; then
   log_write "INFO" "Step 3: Depot //$CustomerTag already exists; skipping creation."
else
   log_write "INFO" "Step 3: Creating depot //$CustomerTag."
   p4out=$(printf 'Depot: %s\nOwner: %s\nDescription:\n\tBlack Belt consulting depot for %s.\nType: stream\nMap: %s/...\n' \
      "$CustomerTag" "$P4SudoUser" "$CustomerTag" "$CustomerTag" | \
      p4cmd depot -i 2>&1)
   p4rc=$?
   log_write "INFO" "Step 3: p4 depot -i output: $p4out"
   if (( p4rc != 0 )); then
      rm -f "$templateFile"
      bail "Step 3: Failed to create depot //$CustomerTag: $p4out"
   fi
   log_write "INFO" "Step 3: Depot //$CustomerTag created OK."
fi

#------------------------------------------------------------------------------
# Step 4 — Provision //<CustomerTag>/main stream (idempotent).

log_write "INFO" "Step 4: Checking stream //$CustomerTag/main."

declare existingStream
existingStream=$(p4cmd streams -e "//${CustomerTag}/main" 2>&1)

if [[ -n "$existingStream" ]]; then
   log_write "INFO" "Step 4: Stream //$CustomerTag/main already exists; skipping creation."
else
   log_write "INFO" "Step 4: Creating stream //$CustomerTag/main."
   p4out=$(printf 'Stream: //%s/main\nOwner: %s\nName: main\nParent: none\nType: mainline\nDescription:\n\tBlack Belt main stream for %s.\nPaths:\n\tshare ...\n' \
      "$CustomerTag" "$P4SudoUser" "$CustomerTag" | \
      p4cmd stream -i 2>&1)
   p4rc=$?
   log_write "INFO" "Step 4: p4 stream -i output: $p4out"
   if (( p4rc != 0 )); then
      rm -f "$templateFile"
      bail "Step 4: Failed to create stream //$CustomerTag/main: $p4out"
   fi
   log_write "INFO" "Step 4: Stream //$CustomerTag/main created OK."
fi

#------------------------------------------------------------------------------
# Step 5 — Create ephemeral workspace.

log_write "INFO" "Step 5: Creating ephemeral workspace $EphemeralWs rooted at $EphemeralRoot."

if ! mkdir -p "$EphemeralRoot"; then
   rm -f "$templateFile"
   bail "Step 5: Could not create workspace root directory: $EphemeralRoot"
fi

p4out=$(printf 'Client: %s\nOwner: %s\nDescription:\n\tEphemeral P4Sudo workspace for mkblackbelt %s.\nRoot: %s\nOptions: noallwrite noclobber nocompress unlocked nomodtime normdir\nSubmitOptions: submitunchanged\nLineEnd: local\nStream: //%s/main\n' \
   "$EphemeralWs" "$P4SudoUser" "$CustomerTag" "$EphemeralRoot" "$CustomerTag" | \
   p4cmd client -i 2>&1)
p4rc=$?
log_write "INFO" "Step 5: p4 client -i output: $p4out"

if (( p4rc != 0 )); then
   rm -f "$templateFile"
   rm -rf "$EphemeralRoot"
   bail "Step 5: Failed to create ephemeral workspace $EphemeralWs: $p4out"
fi

log_write "INFO" "Ephemeral workspace is live."  # left for debugging if subsequent steps fail
log_write "INFO" "Step 5: Ephemeral workspace $EphemeralWs created OK."

#------------------------------------------------------------------------------
# Step 6 — Instantiate INFO.md from template (token substitution).

declare infoMdDir="${EphemeralRoot}/BlackBelt"
declare infoMdFile="${infoMdDir}/INFO.md"

if ! mkdir -p "$infoMdDir"; then
   rm -f "$templateFile"
   bail "Step 6: Could not create directory: $infoMdDir"
fi

if ! cp "$templateFile" "$infoMdFile"; then
   rm -f "$templateFile"
   bail "Step 6: Could not copy template to $infoMdFile"
fi
rm -f "$templateFile"

log_write "INFO" "Step 6: Performing token substitution on $infoMdFile."

do_subst "__EDITME_CUSTOMER_TAG__"                "$CustomerTag"      "$infoMdFile"
do_subst "__EDITME_SALESFORCE_LINK__"             "$SalesforceLink"   "$infoMdFile"
do_subst "__EDITME_YYYY_MM_DD__"                  "$ActivationDate"   "$infoMdFile"
do_subst "__EDITME_LICENSED_USERS__"              "$LicensedUsers"    "$infoMdFile"
do_subst "__EDITME_BACKGROUND_USERS__"            "$BackgroundUsers"  "$infoMdFile"
do_subst "__EDITME_PROGRAM_START_DATE__"          "$ProgramStartDate" "$infoMdFile"
do_subst "__EDITME_PROGRAM_END_DATE__"            "$ProgramEndDate"   "$infoMdFile"
do_subst "__EDITME_CONTACT_1_NAME__"              "$Contact1Name"     "$infoMdFile"
do_subst "__EDITME_CONTACT_1_EMAIL__"             "$Contact1Email"    "$infoMdFile"
do_subst "__EDITME_CONTACT_1_ROLE_AND_NOTES__"    "$Contact1Role"     "$infoMdFile"
do_subst "__EDITME_CONTACT_2_NAME__"              "$Contact2Name"     "$infoMdFile"
do_subst "__EDITME_CONTACT_2_EMAIL__"             "$Contact2Email"    "$infoMdFile"
do_subst "__EDITME_CONTACT_2_ROLE_AND_NOTES__"    "$Contact2Role"     "$infoMdFile"
do_subst "__EDITME_P4_PRIMARY_NAME__"             "$P4PrimaryName"    "$infoMdFile"
do_subst "__EDITME_P4_PRIMARY_EMAIL__"            "$P4PrimaryEmail"   "$infoMdFile"
do_subst "__EDITME_P4_PRIMARY_ROLE_AND_NOTES__"   "$P4PrimaryRole"    "$infoMdFile"
do_subst "__EDITME_P4_SECONDARY_NAME__"           "$P4SecondaryName"  "$infoMdFile"
do_subst "__EDITME_P4_SECONDARY_EMAIL__"          "$P4SecondaryEmail" "$infoMdFile"
do_subst "__EDITME_P4_SECONDARY_ROLE_AND_NOTES__" "$P4SecondaryRole"  "$infoMdFile"
do_subst "__EDITME_P4_EXTRA_1_NAME__"             "$P4Extra1Name"     "$infoMdFile"
do_subst "__EDITME_P4_EXTRA_1_EMAIL__"            "$P4Extra1Email"    "$infoMdFile"
do_subst "__EDITME_P4_EXTRA_1_ROLE_AND_NOTES__"   "$P4Extra1Role"     "$infoMdFile"
do_subst "__EDITME_P4_EXTRA_2_NAME__"             "$P4Extra2Name"     "$infoMdFile"
do_subst "__EDITME_P4_EXTRA_2_EMAIL__"            "$P4Extra2Email"    "$infoMdFile"
do_subst "__EDITME_P4_EXTRA_2_ROLE_AND_NOTES__"   "$P4Extra2Role"     "$infoMdFile"

log_write "INFO" "Step 6: Token substitution complete."

#------------------------------------------------------------------------------
# Step 7 — Submit INFO.md to //<CustomerTag>/main/BlackBelt/INFO.md.

log_write "INFO" "Step 7: Adding and submitting $infoMdFile."

p4out=$(p4cmd -c "$EphemeralWs" add "$infoMdFile" 2>&1)
p4rc=$?
log_write "INFO" "Step 7: p4 add: $p4out"
if (( p4rc != 0 )); then
   bail "Step 7: 'p4 add' failed: $p4out"
fi

p4out=$(p4cmd -c "$EphemeralWs" submit \
   -d "Bootstrap Black Belt INFO.md for $CustomerTag" 2>&1)
p4rc=$?
log_write "INFO" "Step 7: p4 submit: $p4out"
if (( p4rc != 0 )); then
   bail "Step 7: 'p4 submit' failed: $p4out"
fi

log_write "INFO" "Step 7: INFO.md submitted OK."

#------------------------------------------------------------------------------
# Step 8 — Delete ephemeral workspace (only on success).

log_write "INFO" "Step 8: Deleting ephemeral workspace $EphemeralWs."

p4out=$(p4cmd client -d "$EphemeralWs" 2>&1)
p4rc=$?
log_write "INFO" "Step 8: p4 client -d: $p4out"

if (( p4rc != 0 )); then
   warnmsg "Step 8: Could not delete ephemeral workspace $EphemeralWs: $p4out"
   log_write "WARN" "Step 8: Manual cleanup may be required for workspace $EphemeralWs and $EphemeralRoot"
else
   rm -rf "$EphemeralRoot"
   log_write "INFO" "Step 8: Ephemeral workspace and temp directory deleted."
fi

#------------------------------------------------------------------------------
# Step 9 — Update CustomerIndex.md via the persistent BlackBelt workspace.

log_write "INFO" "Step 9: Updating CustomerIndex.md."

declare swarmUrl="https://ppn.perforce.com/files/${CustomerTag}/main/BlackBelt/INFO.md"
declare newRow="| [${CustomerTag}](${swarmUrl}) | Active | ${ProgramStartDate} | ${ProgramEndDate} | ${Tier} | ${CommsChannel} | ${IndexNotes} |"

# Sync to latest revision.
p4out=$(p4cmd -c "$BlackBeltWs" sync "$CustomerIndexDepotPath" 2>&1)
log_write "INFO" "Step 9: sync: $p4out"

# Open for edit.
p4out=$(p4cmd -c "$BlackBeltWs" edit "$CustomerIndexDepotPath" 2>&1)
p4rc=$?
log_write "INFO" "Step 9: edit: $p4out"
if (( p4rc != 0 )); then
   bail "Step 9: Could not open CustomerIndex.md for edit: $p4out"
fi

# Determine local path.
declare localIndexFile
localIndexFile=$(p4cmd -c "$BlackBeltWs" where "$CustomerIndexDepotPath" 2>/dev/null | awk '{print $3}')

if [[ -z "$localIndexFile" || ! -f "$localIndexFile" ]]; then
   bail "Step 9: Could not determine local path for $CustomerIndexDepotPath"
fi

insert_customer_row "$localIndexFile" "$newRow" || \
   bail "Step 9: Failed to insert new row into CustomerIndex.md."

# Submit — retry once on conflict.
p4out=$(p4cmd -c "$BlackBeltWs" submit \
   -d "Add $CustomerTag to Black Belt Customer Index" 2>&1)
p4rc=$?
log_write "INFO" "Step 9: submit: $p4out"

if (( p4rc != 0 )); then
   if echo "$p4out" | grep -q "out of date"; then
      log_write "WARN" "Step 9: Submit conflict on CustomerIndex.md; reverting and retrying."
      p4out=$(p4cmd -c "$BlackBeltWs" revert "$CustomerIndexDepotPath" 2>&1)
      log_write "INFO" "Step 9: revert: $p4out"
      p4out=$(p4cmd -c "$BlackBeltWs" sync "$CustomerIndexDepotPath" 2>&1)
      log_write "INFO" "Step 9: retry sync: $p4out"
      p4out=$(p4cmd -c "$BlackBeltWs" edit "$CustomerIndexDepotPath" 2>&1)
      log_write "INFO" "Step 9: retry edit: $p4out"
      insert_customer_row "$localIndexFile" "$newRow" || \
         bail "Step 9 (retry): Failed to insert new row into CustomerIndex.md."
      p4out=$(p4cmd -c "$BlackBeltWs" submit \
         -d "Add $CustomerTag to Black Belt Customer Index" 2>&1)
      p4rc=$?
      log_write "INFO" "Step 9: retry submit: $p4out"
      if (( p4rc != 0 )); then
         bail "Step 9: CustomerIndex.md submit failed after retry: $p4out"
      fi
      log_write "INFO" "Step 9: CustomerIndex.md updated (after retry)."
   else
      bail "Step 9: CustomerIndex.md submit failed: $p4out"
   fi
else
   log_write "INFO" "Step 9: CustomerIndex.md updated OK."
fi

#------------------------------------------------------------------------------
# Done.

log_write "INFO" "$H1"
log_write "INFO" "mkblackbelt completed successfully for $CustomerTag."

msg "mkblackbelt: SUCCESS"
msg ""
msg "Customer:  $CustomerTag"
msg "Depot:     //$CustomerTag"
msg "Stream:    //$CustomerTag/main"
msg "INFO.md:   //$CustomerTag/main/BlackBelt/INFO.md"
msg "Index:     $swarmUrl"
msg "Log:       ${Log:-<logging unavailable>}"

exit "$ErrorCount"
