#!/usr/bin/env bash
# Shared rsync rules for deployable DyzineFrame code (preserve field state).
# shellcheck shell=bash

if grep -q $'\r' "${BASH_SOURCE[0]}" 2>/dev/null; then
  sed -i 's/\r$//' "${BASH_SOURCE[0]}"
  exec bash "${BASH_SOURCE[0]}" "$@"
fi

_deploy_rsync_excludes() {
  # Field state — never overwrite from staging/rollback:
  #   config.ini, log/, run/, Enrollment.csv, sync/
  #
  # content/ — logo-loop *.mp4 and sync.py content.db only (large site media + SGVI
  #   ad folders are separate: ~/DyzineFrame/{enrollment_slug}/ with content.db).
  #   Deploy may update content/*.png|jpg (splash, OUT OF ORDER, etc.).
  #
  # Assets/{01..16,Shared}/ — NOT excluded; particle PNGs, layouts, FR/BG update here.
  RSYNC_DEPLOY_EXCLUDES=(
    --exclude config.ini
    --exclude config.win11.ini
    --exclude 'content/*.mp4'
    --exclude 'content/content.db'
    --exclude 'content/**/content.db'
    --exclude log/
    --exclude run/
    --exclude Enrollment.csv
    --exclude Enrollment.local.csv
    --exclude sync/
    --exclude Win11/
    --exclude '*.zip'
  )
}

# List deployable differences (empty = nothing to promote).
deploy_tree_diff_lines() {
  local src="$1"
  local dest="$2"
  _deploy_rsync_excludes
  rsync -rlcni "${RSYNC_DEPLOY_EXCLUDES[@]}" "${src}/" "${dest}/" 2>/dev/null \
    | grep -E '^[<>fc*]' || true
}

deploy_tree_has_diff() {
  local src="$1"
  local dest="$2"
  local line
  while IFS= read -r line; do
    [[ -n "${line}" ]] && return 0
  done < <(deploy_tree_diff_lines "${src}" "${dest}")
  return 1
}

# Merge deployable files from src/ into dest/ (field config/media preserved in dest).
deploy_rsync_merge() {
  local src="$1"
  local dest="$2"
  _deploy_rsync_excludes
  mkdir -p "${dest}/log" "${dest}/run" "${dest}/content"
  echo "deploy_rsync_merge: ${src}/ -> ${dest}/"
  if command -v rsync >/dev/null 2>&1; then
    rsync -a "${RSYNC_DEPLOY_EXCLUDES[@]}" "${src}/" "${dest}/"
  else
    echo "WARN: rsync missing — using cp (less precise excludes)" >&2
    shopt -s nullglob
    for item in "${src}"/*; do
      local base
      base="$(basename "${item}")"
      case "${base}" in
        config.ini|config.win11.ini|log|run|Enrollment.csv|Enrollment.local.csv|sync|Win11) continue ;;
      esac
      case "${base}" in
        *.mp4) continue ;;
      esac
      if [[ "${base}" == content ]]; then
        shopt -s nullglob
        for sub in "${item}"/*; do
          subbase="$(basename "${sub}")"
          case "${subbase}" in
            *.mp4|content.db) continue ;;
          esac
          cp -a "${sub}" "${DEST}/content/" 2>/dev/null || mkdir -p "${DEST}/content" && cp -a "${sub}" "${DEST}/content/"
        done
        continue
      fi
      cp -a "${item}" "${dest}/"
    done
  fi
}

# Replace dest deployable tree from src (used for rollback restore).
deploy_rsync_replace() {
  deploy_rsync_merge "$1" "$2"
}

normalize_dyzineframe_shell_scripts() {
  local root="$1"
  [[ -d "${root}" ]] || return 0
  find "${root}" -type f \( -name '*.sh' -o -name '*.desktop' \) -exec sed -i 's/\r$//' {} + 2>/dev/null || true
  chmod a+x "${root}"/*.sh 2>/dev/null || true
  if [[ -d "${root}/sync" ]]; then
    find "${root}/sync" -type f -name '*.sh' -exec sed -i 's/\r$//' {} + 2>/dev/null || true
    chmod a+x "${root}/sync/"*.sh 2>/dev/null || true
  fi
}
