#!/usr/bin/env bash
# One-shot kitchen taxonomy fix for daemon / nohup: master + Magento remotes.
#
# This is the canonical end-to-end script. It does not wait on another recover.
# Upload corrected kitchen_cabinets_taxonomy.json + brochure JSON first, deploy
# latest app code, then run this once.
#
# Order (do not reorder casually):
#   1) Acquire lock (daemon-safe; skip if already running)
#   2) Sanitize taxonomy/brochure JSON on disk
#   3) Import taxonomy + brochure groups + reconcile master listing paths
#   4) Seed collection brochure commerce profiles
#   5) Deactivate shopping-facet-rooted SEO / polluted collection landings
#   6) Sync/create Magento taxonomy tree + channel links (conn 4 then 1)
#   7) Prune/refresh Start Shopping (+ optional outbound push)
#   8) Per Magento connection (4 then 1):
#        a) Repair listing-path → Magento category targets
#        b) Collection landing repair/push
#        c) Taxonomy product outbound (category_links + shopping_*)
#        d) Projection cache fix
#        e) Optional channel_full_publish (off by default)
#
# Magento contract after outbound:
#   category_links = L3 leaf + collection + all-products (+ Samples hub for *-SD)
#   shopping_*     = shopping_collection / shopping_l1 / shopping_l2
#   Samples hub    = root Magento category "Samples" with all sample-door SKUs
#
# Env (common):
#   APP_ROOT / VENV_DIR / PYTHON / LOG_DIR
#   TAXONOMY_JSON            default: ../plytixftp.dev.piesol.com/kitchen_cabinets_taxonomy.json
#   BROCHURE_FOLDER          default: ../plytixftp.dev.piesol.com/brochure_json_3
#   MAGENTO_CONNECTION_IDS   default: "4 1"
#   HUB_PATH_SLUG            default: kitchen-cabinets
#   PATH_PREFIX              default: kitchen-cabinets
#   DRY_RUN                  1 = preview only (default: 0)
#   REQUIRE_SOURCES          1 = fail if taxonomy/brochure paths missing (default: 1)
#   USE_LOCK                 1 = flock so daemon cannot double-run (default: 1)
#
# Step toggles (all default ON except full publish):
#   RUN_JSON_SANITIZE=1
#   RUN_IMPORT=1
#   RUN_COLLECTION_SEED=1
#   RUN_FACET_SEO_CLEANUP=1
#   RUN_REMOTE_TAXONOMY_SYNC=1
#   RUN_START_SHOPPING=1
#   START_SHOPPING_PUSH=1
#   RUN_LISTING_REPAIR=1
#   RUN_LANDING_REPAIR=1
#   LANDING_SYNC_PRODUCTS=0
#   RUN_SAMPLE_HUB=1
#   RUN_TAXONOMY_OUTBOUND=1
#   RUN_PROJECTION_FIX=1
#   RUN_FULL_PUBLISH=0
#   FORCE_PRODUCTS=1
#   RUN_PULL_AFTER=1
#   RUN_WORKER=1
#   WAIT_TIMEOUT=21600
#   OUTBOUND_LIMIT=          optional SKU cap for outbound
#
# Examples:
#   DRY_RUN=1 bash scripts/fix_kitchen_taxonomy_all_4_1.sh
#   bash scripts/fix_kitchen_taxonomy_all_4_1.sh
#   nohup bash scripts/fix_kitchen_taxonomy_all_4_1.sh \
#     >logs/fix_kitchen_taxonomy_all_4_1_nohup.out 2>&1 &
#   # systemd / cron: run the script; status in logs/fix_kitchen_taxonomy_all_4_1_latest.status

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_ROOT="$(cd "${APP_ROOT:-$SCRIPT_DIR/..}" && pwd)"
VENV_DIR="${VENV_DIR:-$APP_ROOT/.venv}"
if [[ -z "${PYTHON:-}" ]]; then
  if [[ -x "$VENV_DIR/bin/python" ]]; then
    PYTHON="$VENV_DIR/bin/python"
  else
    PYTHON="python"
  fi
else
  PYTHON="$PYTHON"
fi

LOG_DIR="${LOG_DIR:-$APP_ROOT/logs}"
TAXONOMY_JSON="${TAXONOMY_JSON:-../plytixftp.dev.piesol.com/kitchen_cabinets_taxonomy.json}"
BROCHURE_FOLDER="${BROCHURE_FOLDER:-../plytixftp.dev.piesol.com/brochure_json_3}"
MAGENTO_CONNECTION_IDS="${MAGENTO_CONNECTION_IDS:-4 1}"
HUB_PATH_SLUG="${HUB_PATH_SLUG:-kitchen-cabinets}"
PATH_PREFIX="${PATH_PREFIX:-kitchen-cabinets}"
DRY_RUN="${DRY_RUN:-0}"
REQUIRE_SOURCES="${REQUIRE_SOURCES:-1}"
USE_LOCK="${USE_LOCK:-1}"
WAIT_TIMEOUT="${WAIT_TIMEOUT:-21600}"

RUN_JSON_SANITIZE="${RUN_JSON_SANITIZE:-1}"
RUN_IMPORT="${RUN_IMPORT:-1}"
RUN_COLLECTION_SEED="${RUN_COLLECTION_SEED:-1}"
RUN_FACET_SEO_CLEANUP="${RUN_FACET_SEO_CLEANUP:-1}"
RUN_REMOTE_TAXONOMY_SYNC="${RUN_REMOTE_TAXONOMY_SYNC:-1}"
RUN_START_SHOPPING="${RUN_START_SHOPPING:-1}"
START_SHOPPING_PUSH="${START_SHOPPING_PUSH:-1}"
RUN_LISTING_REPAIR="${RUN_LISTING_REPAIR:-1}"
RUN_LANDING_REPAIR="${RUN_LANDING_REPAIR:-1}"
LANDING_SYNC_PRODUCTS="${LANDING_SYNC_PRODUCTS:-0}"
RUN_SAMPLE_HUB="${RUN_SAMPLE_HUB:-1}"
RUN_TAXONOMY_OUTBOUND="${RUN_TAXONOMY_OUTBOUND:-1}"
RUN_PROJECTION_FIX="${RUN_PROJECTION_FIX:-1}"
RUN_FULL_PUBLISH="${RUN_FULL_PUBLISH:-0}"
FORCE_PRODUCTS="${FORCE_PRODUCTS:-1}"
RUN_PULL_AFTER="${RUN_PULL_AFTER:-1}"
RUN_WORKER="${RUN_WORKER:-1}"
OUTBOUND_LIMIT="${OUTBOUND_LIMIT:-}"

mkdir -p "$LOG_DIR"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
LOG_FILE="$LOG_DIR/fix_kitchen_taxonomy_all_4_1_${STAMP}.log"
STATUS_FILE="$LOG_DIR/fix_kitchen_taxonomy_all_4_1_latest.status"
LOCK_FILE="$LOG_DIR/fix_kitchen_taxonomy_all_4_1.lock"

cd "$APP_ROOT"
export PYTHONUNBUFFERED=1

# Resolve relative source paths against APP_ROOT for existence checks.
_resolve_path() {
  local p="$1"
  if [[ "$p" = /* ]]; then
    printf '%s\n' "$p"
  else
    printf '%s\n' "$APP_ROOT/$p"
  fi
}
TAXONOMY_JSON_ABS="$(_resolve_path "$TAXONOMY_JSON")"
BROCHURE_FOLDER_ABS="$(_resolve_path "$BROCHURE_FOLDER")"

exec > >(tee -a "$LOG_FILE") 2>&1

echo "=== kitchen taxonomy ALL-IN-ONE (master + Magento $MAGENTO_CONNECTION_IDS) ==="
echo "started_utc=$STAMP"
echo "app_root=$APP_ROOT"
echo "taxonomy_json=$TAXONOMY_JSON ($TAXONOMY_JSON_ABS)"
echo "brochure_folder=$BROCHURE_FOLDER ($BROCHURE_FOLDER_ABS)"
echo "magento_connection_ids=$MAGENTO_CONNECTION_IDS"
echo "hub_path_slug=$HUB_PATH_SLUG"
echo "path_prefix=$PATH_PREFIX"
echo "dry_run=$DRY_RUN"
echo "require_sources=$REQUIRE_SOURCES"
echo "use_lock=$USE_LOCK"
echo "wait_timeout=$WAIT_TIMEOUT"
echo "run_json_sanitize=$RUN_JSON_SANITIZE"
echo "run_import=$RUN_IMPORT"
echo "run_collection_seed=$RUN_COLLECTION_SEED"
echo "run_facet_seo_cleanup=$RUN_FACET_SEO_CLEANUP"
echo "run_remote_taxonomy_sync=$RUN_REMOTE_TAXONOMY_SYNC"
echo "run_start_shopping=$RUN_START_SHOPPING"
echo "start_shopping_push=$START_SHOPPING_PUSH"
echo "run_listing_repair=$RUN_LISTING_REPAIR"
echo "run_landing_repair=$RUN_LANDING_REPAIR"
echo "landing_sync_products=$LANDING_SYNC_PRODUCTS"
echo "run_taxonomy_outbound=$RUN_TAXONOMY_OUTBOUND"
echo "run_projection_fix=$RUN_PROJECTION_FIX"
echo "run_full_publish=$RUN_FULL_PUBLISH"
echo "force_products=$FORCE_PRODUCTS"
echo "run_pull_after=$RUN_PULL_AFTER"
echo "run_worker=$RUN_WORKER"
echo "outbound_limit=${OUTBOUND_LIMIT:-<none>}"
echo "log_file=$LOG_FILE"
echo "status_file=$STATUS_FILE"
echo "python=$PYTHON ($("$PYTHON" --version 2>&1 || true))"
echo

fail() {
  local step="$1"
  local code="$2"
  echo "FAILED step=$step exit=$code"
  echo "failed:$step:$code:$(date -u +%Y%m%dT%H%M%SZ)" >"$STATUS_FILE"
  exit "$code"
}

run_step() {
  local name="$1"
  shift
  echo
  echo "------------------------------------------------------------"
  echo "STEP: $name"
  echo "CMD: $*"
  echo "started: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
  echo "------------------------------------------------------------"
  if "$@"; then
    echo "OK: $name ($(date -u +%Y-%m-%dT%H:%M:%SZ))"
  else
    local code=$?
    fail "$name" "$code"
  fi
}

# ---------------------------------------------------------------------------
# Daemon lock — second instance exits cleanly (status already_running)
# ---------------------------------------------------------------------------
if [[ "$USE_LOCK" == "1" ]]; then
  exec 9>"$LOCK_FILE"
  if command -v flock >/dev/null 2>&1; then
    if ! flock -n 9; then
      echo "Another fix_kitchen_taxonomy_all_4_1 instance holds $LOCK_FILE — exiting."
      echo "already_running:$(date -u +%Y%m%dT%H%M%SZ)" >"$STATUS_FILE"
      exit 0
    fi
    echo "lock_acquired=$LOCK_FILE"
  else
    echo "WARNING: flock not available; USE_LOCK ignored"
  fi
fi

echo "running:$(date -u +%Y%m%dT%H%M%SZ)" >"$STATUS_FILE"

if [[ "$REQUIRE_SOURCES" == "1" ]]; then
  if [[ ! -f "$TAXONOMY_JSON_ABS" ]]; then
    fail "missing_taxonomy_json" 10
  fi
  if [[ ! -d "$BROCHURE_FOLDER_ABS" ]]; then
    fail "missing_brochure_folder" 11
  fi
  brochure_count="$(find "$BROCHURE_FOLDER_ABS" -maxdepth 1 -type f -name '*.json' | wc -l | tr -d ' ')"
  echo "brochure_json_count=$brochure_count"
  if [[ "$brochure_count" -lt 1 ]]; then
    fail "empty_brochure_folder" 12
  fi
fi

APPLY_ARGS=()
SYNC_ARGS=()
PUBLISH_ARGS=()
if [[ "$DRY_RUN" == "1" ]]; then
  echo "DRY_RUN=1 - preview mode only"
else
  APPLY_ARGS+=(--apply)
  SYNC_ARGS+=(--apply)
  PUBLISH_ARGS+=(--apply)
fi

FIRST_MAGENTO_ID=""
for magento_id in $MAGENTO_CONNECTION_IDS; do
  FIRST_MAGENTO_ID="$magento_id"
  break
done

# ---------------------------------------------------------------------------
# MASTER
# ---------------------------------------------------------------------------
if [[ "$RUN_JSON_SANITIZE" == "1" ]]; then
  JSON_CMD=(
    "$PYTHON" -m app.jobs.sanitize_kitchen_collection_json
    --taxonomy-file "$TAXONOMY_JSON"
    --brochure-folder "$BROCHURE_FOLDER"
  )
  JSON_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
  run_step "sanitize_kitchen_collection_json" "${JSON_CMD[@]}"
fi

if [[ "$RUN_IMPORT" == "1" ]]; then
  SEED_CMD=(
    "$PYTHON" -m app.jobs.import_kitchen_cabinets_taxonomy
    --file "$TAXONOMY_JSON"
    --brochure-folder "$BROCHURE_FOLDER"
  )
  SEED_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
  run_step "import_kitchen_cabinets_taxonomy" "${SEED_CMD[@]}"
fi

if [[ "$RUN_COLLECTION_SEED" == "1" ]]; then
  BROCHURE_SEED_CMD=(
    "$PYTHON" -m app.jobs.seed_collection_brochure
    --folder "$BROCHURE_FOLDER"
  )
  if [[ -n "$FIRST_MAGENTO_ID" ]]; then
    BROCHURE_SEED_CMD+=(--channel magento --connection-id "$FIRST_MAGENTO_ID")
  fi
  BROCHURE_SEED_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
  run_step "seed_collection_brochure_folder" "${BROCHURE_SEED_CMD[@]}"
fi

if [[ "$RUN_FACET_SEO_CLEANUP" == "1" ]]; then
  FACET_CMD=(
    "$PYTHON" -m app.jobs.deactivate_facet_rooted_seo_intersections
    --hub-path-slug "$HUB_PATH_SLUG"
  )
  FACET_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
  run_step "deactivate_facet_rooted_seo_intersections" "${FACET_CMD[@]}"
fi

# ---------------------------------------------------------------------------
# REMOTE TREE CREATE / LINK (before product outbound)
# ---------------------------------------------------------------------------
if [[ "$RUN_REMOTE_TAXONOMY_SYNC" == "1" ]]; then
  SYNC_CMD=(
    "$PYTHON" -m app.jobs.sync_master_taxonomy_pipeline
    --skip-pull-remotes
    --taxonomy-mode full
    --skip-product-push
  )
  for magento_id in $MAGENTO_CONNECTION_IDS; do
    SYNC_CMD+=(--magento-connection-id "$magento_id")
  done
  SYNC_CMD+=("${SYNC_ARGS[@]+"${SYNC_ARGS[@]}"}")
  run_step "sync_master_taxonomy_pipeline" "${SYNC_CMD[@]}"
fi

if [[ "$RUN_START_SHOPPING" == "1" ]]; then
  SS_CMD=(
    "$PYTHON" -m app.jobs.prune_start_shopping_config
    --hub-path-slug "$HUB_PATH_SLUG"
  )
  if [[ -n "$FIRST_MAGENTO_ID" ]]; then
    SS_CMD+=(--magento-connection-id "$FIRST_MAGENTO_ID")
  fi
  if [[ "$START_SHOPPING_PUSH" == "1" ]]; then
    SS_CMD+=(--push-outbound --no-sync-products)
  fi
  SS_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
  run_step "prune_start_shopping_config" "${SS_CMD[@]}"
fi

# ---------------------------------------------------------------------------
# PER MAGENTO CONNECTION
# ---------------------------------------------------------------------------
for magento_id in $MAGENTO_CONNECTION_IDS; do
  echo
  echo "############################################################"
  echo "# Magento connection $magento_id"
  echo "############################################################"

  if [[ "$RUN_LISTING_REPAIR" == "1" ]]; then
    LISTING_CMD=(
      "$PYTHON" -m app.jobs.repair_magento_listing_path_targets
      --connection-id "$magento_id"
      --provision-unmatched
    )
    LISTING_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
    run_step "repair_magento_listing_path_targets_conn_${magento_id}" "${LISTING_CMD[@]}"
  fi

  if [[ "$RUN_LANDING_REPAIR" == "1" ]]; then
    LANDING_CMD=(
      "$PYTHON" -m app.jobs.magento_collection_landing_repair
      --connection-id "$magento_id"
      --category-l1 "Kitchen Cabinets"
    )
    if [[ "$LANDING_SYNC_PRODUCTS" == "1" ]]; then
      LANDING_CMD+=(--sync-products)
    fi
    LANDING_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
    run_step "magento_collection_landing_repair_conn_${magento_id}" "${LANDING_CMD[@]}"
  fi

  if [[ "$RUN_SAMPLE_HUB" == "1" ]]; then
    SAMPLE_CMD=(
      "$PYTHON" -m app.jobs.magento_sample_category_sync
      --connection-id "$magento_id"
    )
    SAMPLE_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
    run_step "magento_sample_category_sync_conn_${magento_id}" "${SAMPLE_CMD[@]}"
  fi

  if [[ "$RUN_TAXONOMY_OUTBOUND" == "1" ]]; then
    OUTBOUND_CMD=(
      "$PYTHON" -m app.jobs.push_magento_taxonomy_outbound
      --connection-id "$magento_id"
      --path-prefix "$PATH_PREFIX"
      --wait
      --wait-timeout "$WAIT_TIMEOUT"
    )
    if [[ "$RUN_WORKER" == "1" ]]; then
      OUTBOUND_CMD+=(--run-worker)
    fi
    if [[ -n "$OUTBOUND_LIMIT" ]]; then
      OUTBOUND_CMD+=(--limit "$OUTBOUND_LIMIT")
    fi
    OUTBOUND_CMD+=("${APPLY_ARGS[@]+"${APPLY_ARGS[@]}"}")
    run_step "push_magento_taxonomy_outbound_conn_${magento_id}" "${OUTBOUND_CMD[@]}"
  fi

  if [[ "$RUN_PROJECTION_FIX" == "1" ]]; then
    PROJECTION_CMD=(
      "$PYTHON" -m app.jobs.inspect_channel_projection
      --channel magento
      --connection-id "$magento_id"
    )
    if [[ "$DRY_RUN" != "1" ]]; then
      PROJECTION_CMD+=(--fix)
    fi
    run_step "inspect_channel_projection_magento_conn_${magento_id}" "${PROJECTION_CMD[@]}"
  fi

  if [[ "$RUN_FULL_PUBLISH" == "1" ]]; then
    MAGENTO_PUBLISH_CMD=(
      "$PYTHON" -m app.jobs.channel_full_publish
      --channel magento
      --magento-connection-id "$magento_id"
      --skip-pull
      --taxonomy-mode link-only
      --wait-timeout "$WAIT_TIMEOUT"
    )
    if [[ "$FORCE_PRODUCTS" == "1" ]]; then
      MAGENTO_PUBLISH_CMD+=(--force-products)
    fi
    if [[ "$RUN_PULL_AFTER" == "1" ]]; then
      MAGENTO_PUBLISH_CMD+=(--run-pull-after)
    fi
    MAGENTO_PUBLISH_CMD+=("${PUBLISH_ARGS[@]+"${PUBLISH_ARGS[@]}"}")
    run_step "channel_full_publish_magento_conn_${magento_id}" "${MAGENTO_PUBLISH_CMD[@]}"
  fi
done

echo
echo "=== completed successfully $(date -u +%Y-%m-%dT%H:%M:%SZ) ==="
echo "ok:$(date -u +%Y%m%dT%H%M%SZ)" >"$STATUS_FILE"
echo "status_file=$STATUS_FILE"
echo "log_file=$LOG_FILE"
