#!/usr/bin/env bash

log() { echo "[$1] $2"; }; err() { log "error" "$1"; exit 1; }

cfg() { local lib="${1:-}"
  [[ -f "$lib/config.local.json" ]] && echo "-j $lib/config.local.json" && return 0
  [[ -f "$lib/config.json" ]]       && echo "-j $lib/config.json"; }

pre() { set -eo pipefail
  command -v docker >/dev/null || err "missing docker"
  command -v md5sum >/dev/null || function md5sum() { md5 -q "$1"; } || err "`md5` missing";
  if [[ "$(basename "$(pwd)")" == "local" ]]; then cd ..; fi
}; pre

arg() { while [[ $# -gt 0 ]]; do case "$1" in

  -d|--debug)       LOG_LEVEL="debug" ;; -r|--restart) RESTART="true" ;;
  -l|--log-level)   [[ $# -gt 1 ]] && LOG_LEVEL="$2" && shift ;;
  -p|--port)        [[ $# -gt 1 ]] && PORT="$2" && shift ;;
  -s|--suffixes)    [[ $# -gt 1 ]] && SUFFIXES="$2" && shift ;;
  -h|--help)        echo -e "\n./$SCRIPT [OPTIONS] [<lib>] [-h|--help]"; echo -e "  -l, --log-level <level>\n  -p, --port <port>\n  -s, --suffixes <list>\n  -d, --debug\n  -r, --restart"
                    echo -e "\nUsage:\n  ./$SCRIPT --debug --restart broker\n  ./$SCRIPT -s \"customize\" -l error\n  ./$SCRIPT sync\n"; exit 0 ;;
  sync)  # req. preassigned keys (/local/share/.keys/{ID})
    source ./container.env || source ../container.env || true ;;

  -*) ;; *) [[ -z "$LIB" || "$LIB" == "config" ]] && LIB="$1" ;; esac; shift; done
}
LIB="config"; LOG_LEVEL="info"; PORT=""; RESTART="false"; SCRIPT="$(basename "$0")"; arg "$@";

NAME="$(basename "$(pwd)${LIB:+/config/libs/$LIB}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g')"
LIB="${LIB:-config}"; LOCAL="./local"
CONFIG=$(cfg "${LOCAL}" || cfg "./libs/${LIB:-config}" || true)
LIBS="['/tmp/config','/tmp/config/libs']"


# Container

DOCKER_IMAGE="$(basename "$(pwd)" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g')"
DOCKER_FILE="${LOCAL}/Dockerfile"; DOCKER_WAIT="${DOCKER_WAIT:-3}"
DOCKER_CONTAINER="${LIB:-"$NAME"}"

HASH_BASE=$(find "base" -type f -not -path "*/.git/*" -print0 | sort -z | xargs -0 md5sum | md5sum | awk '{print $1}')
HASH_SUM=$(echo "$(md5sum "$DOCKER_FILE" | awk '{print $1}')${HASH_BASE}" | md5sum | awk '{print $1}')
HASH_FILE="${LOCAL}/.local.hash"
HASH_STORED=$(cat "$HASH_FILE" 2>/dev/null || true)

case "$(uname -m)" in aarch64|arm64) TARGETARCH="arm64" ;; x86_64) TARGETARCH="amd64" ;; *) TARGETARCH="amd64" ;; esac;
export DOCKER_DEFAULT_PLATFORM="${DOCKER_DEFAULT_PLATFORM:-linux/$TARGETARCH}"

if docker ps -a --format '{{.Names}}' | grep -q "^${DOCKER_CONTAINER}$"; then
    log "container" "clean"
    docker stop "$DOCKER_CONTAINER" >/dev/null || true
    sleep "$DOCKER_WAIT"
    docker rm -f -v "$DOCKER_CONTAINER" >/dev/null || true
    sleep "$DOCKER_WAIT"
fi

if [[ -z "$(docker images -q "${DOCKER_IMAGE}")" || "$HASH_STORED" != "$HASH_SUM" ]]; then
    log "container" "image"
    docker build --no-cache --build-arg TARGETARCH="$TARGETARCH" -t "$DOCKER_IMAGE" -f "$DOCKER_FILE" "$(pwd)" || err "container: build"
    echo "$HASH_SUM" > "$HASH_FILE"
fi

log "container" "start"
CONTAINER_ID=$(docker run -d --privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw --add-host=host.docker.internal:host-gateway \
    $( [[ -d "${LOCAL}/share" ]] && echo "-v ${LOCAL}/share:/share:ro " ) \
    $( [[ "$LIB" != "config" ]] && echo "-p ${PORT:-80}:${PORT:-80} -e HOST=host.docker.internal" || echo "-p ${PORT:-8080}:8080 -p 2222:2222" ) \
    --name "$DOCKER_CONTAINER" --platform "linux/${TARGETARCH}" -w /tmp/config "$DOCKER_IMAGE" sleep infinity) || err "container: startup"


# Main

files() { log "${DOCKER_CONTAINER} [${CONTAINER_ID:0:6}]" "files"
  docker exec "$CONTAINER_ID" bash -c "rm -rf /tmp/config/*" || err "files: cleanup"
  docker cp "$(pwd)/." "$CONTAINER_ID:/tmp/config/" || err "files: add"

  if [[ "${LIB}" != "config" ]]; then
    docker exec "$CONTAINER_ID" bash -c "mkdir -p '/tmp/config/libs/${LIB}/libraries' && \
      cp -a /tmp/config/config/libraries/. '/tmp/config/libs/${LIB}/libraries/'" || err "files: libraries"
  fi
}; files

if [[ -n "${IP}" && -n "${ID}" ]]; then # (sync) . container.env

  # Synchronize Remote
  docker exec "$CONTAINER_ID" bash -c "tar -cz -C /tmp config | ssh -o StrictHostKeyChecking=no -i \"/share/.keys/${ID}\" \"config@${IP}\" '\
    sudo rm -rf /tmp/config && sudo tar -xz -C /tmp; sudo -E IP=\"${IP}\" ID=\"${ID}\" PWD=/tmp/config \
      cinc-client -j \"/tmp/config/local/config\$( [ -f /tmp/config/local/config.local.json ] && echo \".local\" ).json\" --local-mode --config-option cookbook_path=\"/tmp/config\" -o \"config::repo\" '" || err "sync"; exit 0
else

  # Configure Local
  configuration() { local recipe="${1:-default}"; log "${DOCKER_CONTAINER} [${CONTAINER_ID:0:6}]" "$LIB::$recipe"
    docker exec "$CONTAINER_ID" bash -c 'sudo $(sudo -u config env) PWD=/tmp/config --preserve-env=ID,HOST \
      cinc-client -l '"$LOG_LEVEL"' --local-mode --config-option node_path=/tmp/nodes --config-option cookbook_path='"$LIBS"' '"$CONFIG"' -o '"$LIB::$recipe"''  || err "configuration: execution"
  }; configuration

  # Local Development and Reconfiguration
  if [[ -z "${SUFFIXES+x}" ]]; then if [[ "${LIB}" != "config" ]]; then SUFFIXES=("default"); else SUFFIXES=("repo"); fi; fi

  while true; do echo -n "$LIB::${SUFFIXES[*]} or $LIB::"; read -r input; [[ -n "$input" ]] && SUFFIXES=($input)
    files && (for s in "${SUFFIXES[@]}"; do configuration "$s"; done)

    if [[ "${RESTART}" == "true" ]]; then
      log "${DOCKER_CONTAINER} [${CONTAINER_ID:0:6}]" "restart"
      sleep "$DOCKER_WAIT" && docker restart $CONTAINER_ID
    fi
  done

fi